您可以透過 Home API for iOS 存取裝置 API。將下列套件匯入應用程式:
import GoogleHomeSDK
import GoogleHomeTypes
詳情請參閱「iOS 資料模型」。
錯誤處理
Home API 中的某些方法會擲回 HomeError,因此建議您使用 do-catch 區塊,在這些呼叫中擷取 HomeError。
處理 HomeError 時,請檢查其 code 和 message 欄位,瞭解錯誤原因。
任何未處理的錯誤都會導致應用程式當機。
詳情請參閱「錯誤處理」。
如需範例,請參閱「將指令傳送至裝置」。
範例呼叫
取得裝置清單
取得 Home 物件的參照後,叫用 devices() 即可取得可存取裝置的 Query。呼叫 Query 的 batched() 方法,每次裝置中繼資料變更時,該方法都會發出反映住家目前狀態的 Set。或呼叫 Query.list() 取得可用裝置的快照。這個方法可讓您輕鬆訂閱 batched() 串流,並傳回第一個發出的值。Query.stream() 會產生串流,在裝置中繼資料 (例如名稱、房間或結構) 變更時發出新值。在內部,這會使用 batched(),且只會發出變更的屬性。
// Get a list of all devices accessible to the user let homeDevices = try await self.home.devices().list()
你可以在這裡查看每部裝置的狀態,並傳送指令給裝置。
在 Home API 1.8 版中,您可以將 devices() 方法的 enableMultipartDevices 參數設為 true,讓 API 將每個多部分裝置視為單一裝置。詳情請參閱「iOS 上的多部分裝置」。
取得裝置類型
如要取得與裝置相關聯的裝置類型,請讀取裝置的 types 屬性,這會傳回 DeviceTypeController。
呼叫 DeviceTypeController.subscribe(_:),訂閱特定裝置類型的更新:
let devices = try await self.home.devices().list() if let device = devices.first(where: { $0.id == myDeviceId }) { var receivedUpdate1 = false var receivedUpdate2 = false device.types.subscribe(OnOffLightDeviceType.self) .assertNoFailure() .sink { device in if !receivedUpdate1 { receivedUpdate1 = true Task { try await device.matterTraits.onOffTrait?.on() } return } if !receivedUpdate2 { receivedUpdate2 = true return } fatalError("Received unexpected update") } }
如果裝置不支援指定的裝置類型,則會傳回立即完成的 Empty
Publisher。
如果裝置支援特定裝置類型,您可以呼叫 get(),取得該類型的控制代碼:
if let device = devices.first(where: { $0.id == myDeviceId }) { let _ = await device.types.get(OnOffLightDeviceType.self) }
如果裝置不支援指定類型,則會傳回 nil。
呼叫 DeviceTypeController.subscribeAll(),取得 DeviceTypeCollection 的 Publisher。這個類別可讓您檢查裝置是否具有特定裝置類型:
if let device = devices.first(where: { $0.id == myDeviceId }) { device.types.subscribeAll() .assertNoFailure() .sink { types in let lightDeviceType = types[OnOffLightDeviceType.self] let fanDeviceType = types[FanDeviceType.self] } }
取得裝置類型特徵
裝置類型是讀取特性的進入點,因為裝置類型會將裝置分解為功能片段 (例如 Matter 中的端點)。
如果裝置具有兩種裝置類型,且兩者可能具有相同特徵,則系統也會考量特徵衝突。舉例來說,如果裝置同時是音箱和可調光燈具,就會有兩個 On/Off 和兩個 Level Control 特性。
如果裝置有兩個名稱相同的特徵,也可能發生另一種特徵衝突。舉例來說,onOff 可能代表標準 OnOff 特性的例項,也可能代表製造商定義的 OnOff 特性例項。為避免對預期特質產生任何潛在混淆,請透過每種裝置類型的兩個特質集合之一參照特質。
如果是標準特徵,也就是類似 Matter 標準叢集的特徵,請使用 matterTraits。舉例來說,如要取得可調光燈具裝置類型的特定特徵,請按照下列步驟操作:
if let dimmableLightDeviceType = await device.types.get(DimmableLightDeviceType.self) { // Accessing standard trait on the type. let levelControlTrait = dimmableLightDeviceType.matterTraits.levelControlTrait.self }
如果是 Google 特性,請使用 googleTraits:
if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) { // Accessing Google trait on the type. let doorbellPressTrait = doorbellDeviceType.traits[Google.DoorbellPressTrait.self] }
如要存取製造商專屬特徵,請透過 traits 屬性參照,並在前面加上製造商的套件名稱:
let deviceType = await device1?.types.get(OnOffLightDeviceType.self) // Accessing custom trait on the type. if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] { let rpmVal = spinnerTrait.attributes.rpm }
讀取裝置狀態
請參考以下範例,瞭解如何檢查裝置 On/Off 特性的 OnOff 屬性:
let lightDevices = devices.filter { $0.types.contains(OnOffLightDeviceType.self) } let light1 = lightDevices.first let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self) if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait { let onOffVal = onOffTrait.attributes.onOff }
取得具有特定特性的裝置清單
如要取得具有特定特性的裝置清單,您必須逐一檢查裝置、每部裝置的裝置類型,以及每種裝置類型的特性。舉例來說,如要取得住家中所有具有 On/Off 特性的裝置清單:
// Get all light devices that support levelControl var levelControlDevices: [HomeDevice] = [] let allDevices = try await home.devices().list() for device in allDevices { if let deviceType = await device.types.get(OnOffLightDeviceType.self) { if deviceType.traits.contains(Matter.LevelControlTrait.self) { levelControlDevices.append(device) } } }
如需 Home API 提供的完整特徵清單,請參閱「iOS 特徵索引」。
取得裝置類型相似的裝置清單
如要取得代表住家中所有燈具的裝置清單,請按照下列步驟操作:
// Get a list of devices with similar device types (lights) let lightDevices = try await self.home.devices().list().compactMap { $0.types.contains(DimmableLightDeviceType.self) || $0.types.contains(OnOffLightDeviceType.self) || $0.types.contains(ColorTemperatureLightDeviceType.self) || $0.types.contains(ExtendedColorLightDeviceType.self) }
Home API 中有多種裝置類型,可代表核心裝置類型。舉例來說,沒有「Light」裝置類型。如上述範例所示,有四種不同的裝置類型可以代表燈具。因此,如要全面瞭解住家中較高層級的裝置類型,必須納入多種裝置類型。
如需 Home API 提供的裝置類型和特徵完整清單,請參閱「iOS 支援的裝置類型」。
取得裝置的供應商名稱、供應商 ID 或產品 ID
BasicInformationTrait 特性包含裝置的供應商 ID、產品 ID、產品名稱和序號等資訊:
guard let vendorName = basicInfoTrait.attributes.vendorName else { fatalError("Failed to get vendorName") } guard let vendorID = basicInfoTrait.attributes.vendorID else { fatalError("Failed to get vendorID") } guard let productID = basicInfoTrait.attributes.productID else { fatalError("Failed to get productID") }
裝置製造商的雲端對雲端裝置識別
如果您是裝置製造商,且製造 Cloud-to-cloud 裝置,為了透過 BasicInformation 特性識別 Cloud-to-cloud 裝置,您可以在 SYNC 回應中加入下列字串欄位:
Connectivity Standards Alliance (Alliance) 核發的供應商 ID:
"matterOriginalVendorId": "0xfff1",用來識別供應商產品的專屬產品 ID:
"matterOriginalProductId": "0x1234",裝置的專屬 ID,由製造商以特定方式建構:
"matterUniqueId": "matter-device-id",
輸入這些字串欄位時,請使用 Matter 供應商和產品 ID (如有)。如果您不是 Alliance 成員,且未獲派這些 ID,可以將 matterOriginalVendorId 和 matterOriginalProductId 欄位留空,並提供 matterUniqueId 做為 ID。
以下 SYNC 回應範例顯示這些欄位的用法:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"agentUserId": "1836.15267389",
"devices": [
{
"id": "456",
"type": "action.devices.types.LIGHT",
"traits": [
"action.devices.traits.OnOff",
"action.devices.traits.Brightness",
"action.devices.traits.ColorSetting",
],
"willReportState": true,
"deviceInfo": { ... },
"matterOriginalVendorId": "0xfff1",
"matterOriginalProductId": "0x1234",
"matterUniqueId": "matter-device-id",
"otherDeviceIds": [
{
"deviceId": "local-device-id",
}
]
}
]
}
}
詳情請參閱 Cloud-to-cloud SYNC 說明文件。
裝置和特質中繼資料
Home API 中的裝置和特徵具有相關聯的中繼資料,有助於管理應用程式中的使用者體驗。
Home API 中的每個特質都包含 sourceConnectivity 屬性,其中包含特質的線上狀態和位置 (本機或遠端轉送) 資訊。
取得裝置的主要類型
部分裝置可能會透過 Home API 顯示多種裝置類型。為確保使用者在應用程式中看到適合其裝置的選項 (例如裝置控制和建議的自動化動作),建議您檢查裝置類型是否為裝置的主要類型。
if let deviceType = await device?.types.get(HumiditySensorDeviceType.self) { if deviceType.metadata.isPrimaryType { print("Humidity Sensor is the primary type on this device.") } else { print("Humidity Sensor isn't the primary type on this device.") } }
檢查特性的線上狀態
讀取 connectivityState 屬性,檢查特性的連線狀態:
let levelControlConnectivity = levelControlTrait.metadata.sourceConnectivity .connectivityState
如果裝置未連上網際網路,某些特徵 (通常是 Google smart home 特徵) 可能會顯示為離線。這是因為這些特徵是以雲端式為基礎,沒有本機路由。
檢查裝置的連線能力
系統實際上會檢查裝置類型層級的裝置連線能力,因為部分裝置支援多種裝置類型。傳回的狀態是該裝置所有特性的連線狀態組合。
let lightConnectivity = dimmableLightDeviceType.metadata.sourceConnectivity .connectivityState
如果裝置類型不一,且沒有網際網路連線,可能會看到 partiallyOnline 狀態。由於本機路由,Matter 標準特徵可能仍會上線,但雲端式特徵會離線。
取得裝置的 IP 位址
如要找出裝置的 IP 位址,請使用 GeneralDiagnosticsTrait 的 networkInterfaces 屬性。位址會以 Data 物件的形式傳回,您可以使用 Network 架構將其格式化為標準 IPv4 或 IPv6 字串:
func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
let interfaces = trait.attributes.networkInterfaces ?? []
var ipAddresses: [String] = []
for interface in interfaces {
for data in interface.iPv4Addresses {
if let ipv4 = IPv4Address(data) {
ipAddresses.append(String(describing: ipv4))
}
}
for data in interface.iPv6Addresses {
if let ipv6 = IPv6Address(data) {
ipAddresses.append(String(describing: ipv6))
}
}
}
return ipAddresses
}
檢查特性的網路轉送
Home API 也提供特性的位置資訊。dataSourceLocality 表示特徵是透過遠端 (雲端)、本機 (本機中樞) 或點對點 (直接從裝置到裝置,不透過中樞) 轉送。
舉例來說,當應用程式正在啟動,且尚未連上中樞或伺服器來連線裝置時,可能會出現未知的區域值 unspecified。這些裝置無法連線,因此無法處理指令或事件的互動要求。客戶應自行決定如何處理這類裝置。
let levelControlLocality = levelControlTrait.metadata.sourceConnectivity .dataSourceLocality
檢查裝置的網路路由
與連線能力一樣,系統會在裝置類型層級檢查位置。傳回的狀態是該裝置上所有特性的位置組合。
let lightLocality = dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality
在與 partiallyOnline 連線能力類似的情況下,可能會觀察到 mixed 狀態:部分特徵是以雲端式為基礎,其他特徵則位於本機。
變更裝置名稱
呼叫 setName(_:) 方法,變更裝置名稱:
let updatedDevice = try await theDevice.setName("new device name")
變更裝置名稱時,原始 HomeDevice struct 會維持不變,變更會反映在傳回的更新 HomeDevice 物件中。
如果名稱超過 60 個 Unicode 碼點 (字元) 限制,系統會截斷名稱,且不會擲回任何錯誤。開發人員必須負責處理過長的名稱,例如決定是否要通知使用者名稱會遭到截斷。
查看裝置的群組成員資格
實體裝置可以屬於一或多個裝置群組。如要檢查裝置屬於哪些群組,請查看裝置上的 GroupMembershipTrait:
if let trait = await device.traits.get(Google.GroupMembershipTrait.self) {
for groupId in trait.attributes.groupObjectIdsArray {
print("Device belongs to group: \(groupId)")
}
}
如要檢查 DeviceGroup 支援的裝置類型,並將指令傳送至群組做為單一實體,請參閱「控制裝置群組」。