适用于 iOS 的边界路由器设备指南

iOS 应用开发者可以使用 Home API 管理 Thread 边界路由器。

GoogleBorderRouterDevice 是使用两个主要设备特征实现的: ThreadNetworkCapabilitiesTrait, 它提供只读属性来检查边界路由器功能;以及 ThreadNetworkManagementTrait, 它使用专员的临时预共享密钥 (ePSKc) 处理网络生命周期命令和凭据共享。结构级 互联网访问政策使用 ThreadNetworkSettingsTrait 特征进行管理。

在使用任何功能或尝试更新属性之前,请务必检查设备是否支持属性和命令。如需了解详情,请参阅在 Control devices on iOS 上控制设备。

Home API 设备类型 特征 Swift 示例应用 使用场景

边界路由器

GoogleBorderRouterDeviceType

home.matter.6006.types.0161

必需的特征
     google ThreadNetworkCapabilitiesTrait
     google ThreadNetworkManagementTrait

边界路由器

获取有关设备的基本信息

BasicInformation 特征包含设备的相关信息,例如供应商名称、供应商 ID、产品 ID、 产品名称(包括型号信息)和软件版本:

let vendorName = basicInfoTrait.attributes.vendorName!
let vendorID = basicInfoTrait.attributes.vendorID!
let productID = basicInfoTrait.attributes.productID!
let productName = basicInfoTrait.attributes.productName!
let softwareVersion = basicInfoTrait.attributes.softwareVersion!

检查边界路由器功能

您可以使用 ThreadNetworkCapabilitiesTrait 特征检查边界路由器的只读功能(例如 ePSKc 支持和互联网访问设置配置)。

func checkBorderRouterCapabilities(device: HomeDevice) async {
    // Filter for GoogleBorderRouterDevice device type
    guard let gtbrDevice = device.type(Google.GoogleBorderRouterDevice.self) else {
        print("Device is not a Google border router.")
        return
    }

    // Retrieve the ThreadNetworkCapabilitiesTrait
    guard let capabilitiesTrait = gtbrDevice.traits(Google.ThreadNetworkCapabilitiesTrait.self) else {
        print("ThreadNetworkCapabilitiesTrait not found on device.")
        return
    }

    do {
        let isEpskcSupported = try await capabilitiesTrait.epskcSupported.read()
        let internetAccessOption = try await capabilitiesTrait.internetAccessOption.read()
        let isIasSupported = internetAccessOption != .none

        print("ePSKc Supported: \(isEpskcSupported)")
        print("Internet Access Setting Supported: \(isIasSupported)")
    } catch {
        print("Failed to read capabilities: \(error)")
    }
}

管理 Thread 凭据共享 (ePSKc)

Thread 凭据共享是使用专员的临时预共享密钥 (ePSKc) 实现的。ePSKc 模式会生成一个临时的安全密码,外部设备或专员可以使用该密码安全地获取 Thread 网络数据集。

启用 ePSKc 模式

func startEpskcSession(device: HomeDevice, durationSeconds: Int16) async -> Google.ThreadNetworkManagementTrait.ActivateEpskcModeResponse? {
    guard let gtbrDevice = device.type(Google.GoogleBorderRouterDevice.self),
          let mgmtTrait = gtbrDevice.traits(Google.ThreadNetworkManagementTrait.self) else {
        print("ThreadNetworkManagementTrait not found.")
        return nil
    }

    do {
        var request = Google.ThreadNetworkManagementTrait.ActivateEpskcModeRequest()
        request.requestedDurationSeconds = durationSeconds

        let response = try await mgmtTrait.activateEpskcMode(request)

        print("ePSKc Session Activated!")
        print("Status: \(response.status)")
        print("Ephemeral PSKc: \(response.epskc)")
        print("Valid Duration (s): \(response.validDurationSeconds)")

        return response
    } catch {
        print("Failed to activate ePSKc mode: \(error)")
        return nil
    }
}

停用 ePSKc 模式

func stopEpskcSession(device: HomeDevice) async {
    guard let gtbrDevice = device.type(Google.GoogleBorderRouterDevice.self),
          let mgmtTrait = gtbrDevice.traits(Google.ThreadNetworkManagementTrait.self) else {
        return
    }

    do {
        try await mgmtTrait.deactivateEpskcMode(Google.ThreadNetworkManagementTrait.DeactivateEpskcModeRequest())
        print("ePSKc mode deactivated.")
    } catch {
        print("Failed to deactivate ePSKc mode: \(error)")
    }
}

观察 ePSKc 停用事件

当 ePSKc 会话结束时(例如,因为密钥已被使用、会话已过期或会话已被手动取消),Thread 边界路由器会发出事件。

func observeEpskcEvents(device: HomeDevice) async {
    guard let gtbrDevice = device.type(Google.GoogleBorderRouterDevice.self),
          let mgmtTrait = gtbrDevice.traits(Google.ThreadNetworkManagementTrait.self) else {
        return
    }

    do {
        for try await event in mgmtTrait.epskcModeDeactivatedEvent.stream() {
            print("ePSKc Session Ended. Reason: \(event.reason)")
            switch event.reason {
            case .keyUsed:
                print("Key was successfully used to commission a device.")
            case .expired:
                print("Session timed out before the key was used.")
            case .cancelled:
                print("Session was manually cancelled.")
            @unknown default:
                print("Unknown deactivation reason.")
            }
        }
    } catch {
        print("Error streaming ePSKc events: \(error)")
    }
}

管理 Thread 网络成员资格

您可以向 Thread 边界路由器发出命令,让其加入新的 Thread 网络(通过提供活跃的 Operational Dataset TLV),也可以命令其离开当前网络。

func joinNetwork(device: HomeDevice, datasetTlvs: Data) async {
    guard let gtbrDevice = device.type(Google.GoogleBorderRouterDevice.self),
          let mgmtTrait = gtbrDevice.traits(Google.ThreadNetworkManagementTrait.self) else {
        return
    }

    do {
        var request = Google.ThreadNetworkManagementTrait.JoinNetworkRequest()
        request.operationalDatasetTlvs = datasetTlvs

        let response = try await mgmtTrait.joinNetwork(request)
        print("Join network command sent. Status: \(response.status)")
    } catch {
        print("Join network failed: \(error)")
    }
}

func leaveNetwork(device: HomeDevice) async {
    guard let gtbrDevice = device.type(Google.GoogleBorderRouterDevice.self),
          let mgmtTrait = gtbrDevice.traits(Google.ThreadNetworkManagementTrait.self) else {
        return
    }

    do {
        try await mgmtTrait.leaveNetwork(Google.ThreadNetworkManagementTrait.LeaveNetworkRequest())
        print("Leave network command sent successfully.")
    } catch {
        print("Leave network failed: \(error)")
    }
}

配置结构级互联网访问权限

ThreadNetworkSettings 特征是附加到 Structure(代表住宅或建筑物)的可更新特征。它允许开发者为 Thread 边界路由器配置结构级互联网访问政策。

func updateStructureInternetAccess(structure: Structure, enableInternetAccess: Bool) async {
    guard let settingsTrait = structure.traits(Google.ThreadNetworkSettingsTrait.self) else {
        print("ThreadNetworkSettingsTrait not found on structure.")
        return
    }

    let option: Google.ThreadNetworkSettingsTrait.InternetAccessOption = enableInternetAccess ? .internetAccessOptionAll : .internetAccessOptionNone

    do {
        try await settingsTrait.update { mutator in
            mutator.internetAccessOption = option
        }
        print("Successfully updated Thread internet access policy.")
    } catch {
        print("Failed to update Thread internet access policy: \(error)")
    }
}