Przewodnik po urządzeniach z routerem granicznym na iOS

Deweloperzy aplikacji na iOS mogą używać interfejsów Home API do zarządzania Thread Border Router (TBR).

Element GoogleBorderRouterDevice jest implementowany przy użyciu 2 głównych cech urządzenia: ThreadNetworkCapabilitiesTrait, która udostępnia atrybuty tylko do odczytu umożliwiające sprawdzanie funkcji border router, oraz ThreadNetworkManagementTrait, która obsługuje polecenia dotyczące cyklu życia sieci i udostępniania danych logowania przy użyciu tymczasowego klucza wstępnego dla komisarza (ePSKc). Zasady dostępu do internetu na poziomie struktury są zarządzane za pomocą ThreadNetworkSettingsTrait cechy.

Zanim zaczniesz korzystać z jakichkolwiek funkcji lub spróbujesz zaktualizować atrybuty, zawsze sprawdź, czy urządzenie obsługuje daną cechę lub polecenie. Więcej informacji znajdziesz w artykule Sterowanie urządzeniami w usłudze iOS.

Typ urządzenia w interfejsach Home API Cechy Przykładowa aplikacja w Swift Przypadek użycia

Router graniczny

GoogleBorderRouterDeviceType

home.matter.6006.types.0161

Wymagane cechy
     google ThreadNetworkCapabilitiesTrait
     google ThreadNetworkManagementTrait

Router graniczny

Pobieranie podstawowych informacji o urządzeniu

   Zaimplementowane w przykładowej aplikacji na iOS   

Cechy BasicInformation obejmują takie informacje jak nazwa dostawcy, identyfikator dostawcy, identyfikator produktu, nazwa produktu (w tym informacje o modelu) i wersja oprogramowania urządzenia:

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!

Sprawdzanie możliwości routera granicznego

Za pomocą cechy ThreadNetworkCapabilitiesTrait możesz sprawdzić możliwości border router's tylko do odczytu (np. obsługę ePSKc i konfigurację ustawienia dostępu do internetu).

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)")
    }
}

Zarządzanie udostępnianiem danych logowania do sieci Thread (ePSKc)

Udostępnianie danych logowania do sieci Thread odbywa się za pomocą tymczasowego klucza wstępnego dla komisarza (ePSKc). Tryb ePSKc generuje tymczasowy, bezpieczny klucz dostępu, którego urządzenia zewnętrzne lub komisarze mogą używać do bezpiecznego uzyskiwania zbioru danych sieci Thread.

Aktywowanie trybu 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
    }
}

Dezaktywowanie trybu 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)")
    }
}

Obserwowanie zdarzeń dezaktywacji ePSKc

TBR emitują zdarzenia, gdy sesja ePSKc się kończy (np. z powodu użycia klucza, wygaśnięcia sesji lub ręcznego anulowania).

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)")
    }
}

Zarządzanie członkostwem w sieci Thread

Możesz wysłać do TBR polecenie dołączenia do nowej sieci Thread, podając aktywne TLV zbioru danych operacyjnych, lub polecenie opuszczenia bieżącej sieci.

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)")
    }
}

Konfigurowanie dostępu do internetu na poziomie struktury

Cechy ThreadNetworkSettings to cechy, które można aktualizować i które są powiązane ze Structure (reprezentującą dom lub budynek). Umożliwiają one deweloperom konfigurowanie zasad dostępu do internetu w całej strukturze w przypadku TBRów.

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)")
    }
}