Thread Network SDK na Androida

Pakiet Thread Network SDK udostępnia funkcje podobne do cyfrowego pęku kluczy, dzięki czemu aplikacje na Androida mogą udostępniać dane logowania do sieci Thread usługom Google Play. Dzięki temu aplikacje mogą konfigurować dowolne urządzenia Thread z dowolnego ekosystemu inteligentnego domu bez bezpośredniego ujawniania danych logowania i danych użytkownika.

Za pomocą kilku wywołań interfejsu API możesz:

  1. Poproś Usługi Google Play o preferowane dane logowania do sieci Thread.
  2. Skonfiguruj nowe urządzenia Thread Border Router (TBR) i dodaj dane uwierzytelniające sieci Thread do Usług Google Play.
  3. Jeśli masz już urządzenia TBR, możesz sprawdzić, czy są TBRone w preferowanej sieci, i w razie potrzeby je przenieść.

Należy wziąć pod uwagę kilka ścieżek użytkowników i programistów. W tym przewodniku omówimy większość z nich, a także inne kluczowe funkcje i zalecane zastosowania.

Kluczowa terminologia i pojęcia związane z interfejsem API

Zanim zaczniesz, zapoznaj się z tymi terminami:

  • Dane logowania do sieci Thread: binarny obiekt blob TLV Thread, który koduje nazwę sieci Thread, klucz sieciowy i inne właściwości wymagane przez urządzenie Thread do dołączenia do danej sieci Thread.

  • Preferowane dane logowania do sieci Thread: automatycznie wybrane dane logowania do sieci Thread, które można udostępniać aplikacjom różnych dostawców za pomocą interfejsu API getPreferredCredentials.

  • Identyfikator agenta granicznego: 16-bajtowy globalnie unikalny identyfikator urządzenia TBR. Ten identyfikator jest tworzony przez dostawców border router, którzy nim zarządzają.

  • Aplikacja do konfiguracji TBR: to aplikacja na Androida, która konfiguruje nowe urządzenia TBR i dodaje dane logowania do sieci Thread do Usług Google Play. Twoja aplikacja jest autorytatywnym właścicielem dodanych danych logowania i ma do nich dostęp.

Wiele interfejsów Thread Network API zwraca zadanie, które jest wykonywane asynchronicznie. Możesz użyć addOnSuccessListener i addOnFailureListener, aby zarejestrować wywołania zwrotne do otrzymywania wyniku. Więcej informacji znajdziesz w dokumentacji Task.

Własność i utrzymanie danych logowania

Aplikacja, która dodaje dane uwierzytelniające sieci Thread, staje się ich właścicielem i ma pełne uprawnienia dostępu do nich. Jeśli spróbujesz uzyskać dostęp do danych logowania dodanych przez inne aplikacje, pojawi się błąd PERMISSION_DENIED.

Zalecamy, aby właściciel aplikacji aktualizował dane logowania przechowywane w usługach Google Play, gdy sieć TBR zostanie zaktualizowana. Oznacza to dodawanie danych logowania, gdy jest to wymagane, aktualizowanie danych logowania, gdy zmieniają się dane logowania sieci Thread urządzenia border router, oraz usuwanie danych logowania, gdy urządzenie TBR zostanie usunięte lub przywrócone do ustawień fabrycznych.

Wykrywanie agenta granicznego

Dane logowania muszą być zapisane z identyfikatorem agenta granicznego. Musisz się upewnić, że aplikacja do konfiguracji TBR może określić identyfikatory agentów granicznych Twoich urządzeń TBR.

TBR musi używać mDNS do rozgłaszania informacji o sieci Thread, w tym nazwy sieci, rozszerzonego identyfikatora PAN i identyfikatora agenta granicznego. Odpowiednie wartości txt dla tych atrybutów to odpowiednio nn, xp i id.

W przypadku sieci z Google Thread Border Router (gTBR) Usługi Google Play automatycznie pobierają dane logowania do sieci Thread od Google.

Integrowanie pakietu SDK z aplikacją na Androida

Aby rozpocząć, wykonaj te czynności:

  1. Postępuj zgodnie z instrukcjami podanymi w artykule Konfigurowanie Usług Google Play.

  2. Dodaj zależność Usług Google Play do pliku build.gradle:

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. Opcjonalnie: zdefiniuj klasę danych BorderAgent, aby przechowywać informacje o TBR. W tym przewodniku będziemy używać tych danych:

    data class BorderAgentInfo(
      // Network Name max 16 len
      val networkName: String = "",
      val extPanId: ByteArray = ByteArray(16),
      val borderAgentId: ByteArray = ByteArray(16),
      ...
    )
    

Następnie omówimy zalecane kroki dodawania preferowanych danych logowania i zarządzania nimi.

Konfiguracja nowych routerów granicznych Thread

Zanim utworzysz nową sieć dla nowych routerów granicznych, najpierw spróbuj użyć danych logowania do preferowanej sieci. Dzięki temu urządzenia Thread są połączone z jedną siecią Thread, gdy jest to możliwe.

Wywołanie metody getPreferredCredentials uruchamia aktywność, która prosi użytkowników o zezwolenie na żądanie sieciowe. Jeśli dane uwierzytelniające sieci zostały zapisane w cyfrowym pęku kluczy pakietu Thread SDK, zostaną one zwrócone do aplikacji.

Poproś o dane logowania

Aby poprosić użytkownika o preferowane dane logowania:

  1. Zadeklaruj ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Obsłuż wynik aktywności zwrócony jako ThreadNetworkCredentials:

    preferredCredentialsLauncher =
     registerForActivityResult(
       StartIntentSenderForResult()
     ) { result: ActivityResult ->
       if (result.resultCode == RESULT_OK) {
         val threadNetworkCredentials = ThreadNetworkCredentials.fromIntentSenderResultData(result.data!!)
         Log.d("debug", threadNetworkCredentials.networkName)
       } else {
         Log.d("debug", "User denied request.")
       }
     }
    
  3. Jeśli konfigurujesz nową aktywność TBR, zalecamy wywołanie preferredCredentials i uruchomienie aktywności. To wywołanie sprawi, że nowa karta TBR będzie używać tych samych danych logowania, które są już zapisane jako preferowane na telefonie, co ułatwi konwergencję różnych kart TBR w tej samej sieci.

    private fun getPreferredThreadNetworkCredentials() {
      ThreadNetwork.getClient(this)
        .preferredCredentials
      .addOnSuccessListener { intentSenderResult ->
        intentSenderResult.intentSender?.let {
          preferredCredentialsLauncher.launch(IntentSenderRequest.Builder(it).build())
          } ?: Log.d("debug", "No preferred credentials found.")
        }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
    }
    
  4. Jeśli Twój przypadek użycia dotyczy konfigurowania urządzeń, które nie są routerami Thread, np. nowego urządzenia końcowego Matter-over-Thread, zalecamy użycie interfejsu API allActiveCredentials do pobierania danych logowania. To wywołanie skanuje w poszukiwaniu TBR-ów znalezionych w sieci lokalnej, więc nie zwraca danych logowania, które nie są dostępne lokalnie przez istniejący TBR.

    // Creates the IntentSender result launcher for the getAllActiveCredentials API
    private val getAllActiveCredentialsLauncher =
      registerForActivityResult(
        StartIntentSenderForResult()
      ) { result: ActivityResult ->
        if (result.resultCode == RESULT_OK) {
          val activeCredentials: List<ThreadNetworkCredentials> =
            ThreadNetworkCredentials.parseListFromIntentSenderResultData(
              result.data!!
            )
          // Use the activeCredentials list
        } else {
          // The user denied to share!
        }
      }
    
    // Invokes the getAllActiveCredentials API and starts the dialog activity with the returned
    // IntentSender
    threadNetworkClient
    .getAllActiveCredentials()
    .addOnSuccessListener { intentSenderResult: IntentSenderResult ->
      val intentSender = intentSenderResult.intentSender
      if (intentSender != null) {
        getAllActiveCredentialsLauncher.launch(
          IntentSenderRequest.Builder(intentSender).build()
        )
      } else {
        // No active network credentials found!
      }
    }
    // Handles the failure
    .addOnFailureListener { e: Exception ->
      // Handle the exception
    }
    

Tworzenie nowej sieci Thread

Jeśli w sieci Thread użytkownika nie ma preferowanych ani aktywnych danych logowania, możesz użyć interfejsu API addCredentials, aby dodać dane logowania do Usług Google Play. Aby to zrobić, musisz utworzyć ThreadBorderAgent i podać obiekt ThreadNetworkCredentials.

Aby utworzyć losową sieć, wywołaj newRandomizeBuilder:

val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()

Aby określić nazwę sieci Thread:

val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
  .setNetworkName("ThreadNetworkSDK")
  .build()

Dodawanie danych logowania

Aby dane logowania do sieci Thread były dostępne dla innych dostawców Thread, musimy dodać je do Usług Google Play. Zanim dodamy nowe dane logowania, musimy też wiedzieć, do którego urządzenia TBR należy ta sieć Thread.

W tym przykładzie utworzymy ThreadBorderAgent na podstawie identyfikatora agenta granicznego i przekażemy nowo utworzone dane logowania do sieci Thread:

private fun addCredentials(borderAgentInfo: BorderAgentInfo, credentialsToBeAdded: ThreadNetworkCredentials) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  ThreadNetwork.getClient(this)
    .addCredentials(threadBorderAgent, credentialsToBeAdded)
      .addOnSuccessListener {
        Log.d("debug", "Credentials added.")
      }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Wykrywanie i migracja border routerów w terenie

Jeśli masz border router w terenie, możesz użyć isPreferredCredentials, aby sprawdzić, czy border router należą do preferowanej sieci. Ten interfejs API nie prosi użytkownika o uprawnienia i sprawdza dane logowania border router pod kątem danych przechowywanych w usługach Google Play.

Funkcja isPreferredCredentials zwraca wartość 0 w przypadku braku dopasowania i 1 w przypadku dopasowania jako typ danych Int. Aby sprawdzić wyniki, możesz użyć IsPreferredCredentialsResult.

public @interface IsPreferredCredentialsResult {
    int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
    int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
    int PREFERRED_CREDENTIALS_MATCHED = 1;
}

Aby używać isPreferredCredentials, musisz najpierw utworzyć obiekt ThreadNetworkCredentials. Istnieje kilka sposobów na utworzenie instancji ThreadNetworkCredentials. W kolejnych krokach omówimy te opcje.

Dane logowania do sieci Thread według operacyjnego zbioru danych

W niektórych przypadkach urządzenie TBR jest już skonfigurowane z siecią Thread i chcesz dodać tę sieć do Usług Google Play, aby udostępnić ją innym dostawcom. Możesz utworzyć instancję ThreadNetworkCredential z nieprzetworzonej listy TLV aktywnego operacyjnego zbioru danych Thread:

  1. Przekonwertuj operacyjny zbiór danych na ByteArray. Na przykład:

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. Użyj fromActiveOperationalDataset, aby utworzyć ThreadNetworkCredentials. Jeśli się uda, zobaczysz nazwę sieci Thread, kanał i inne informacje o sieci. Pełną listę właściwości znajdziesz w artykule ThreadNetworkCredentials.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. Wywołaj interfejs API isPreferredCredentials i przekaż ThreadNetworkCredentials.

    ThreadNetwork.getClient(this)
    .isPreferredCredentials(threadNetworkCredentials)
    .addOnSuccessListener { result ->
      when (result) {
        IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_MATCHED ->
            Log.d("isPreferredCredentials", "Credentials not matched.")
        IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_MATCHED ->
            Log.d("isPreferredCredentials", "Credentials matched.")
      }
    }
    .addOnFailureListener { e: Exception -> Log.d("isPreferredCredentials", "ERROR: [${e}]") }
    

Dane logowania do sieci Thread według agenta granicznego

Identyfikator agenta granicznego jednoznacznie identyfikuje urządzenie TBR. Aby używać interfejsu API getCredentialsByBorderAgent, musisz najpierw utworzyć obiekt ThreadBorderAgent i podać identyfikator agenta granicznego.

Po utworzeniu obiektu ThreadBorderAgent wywołaj getCredentialsByBorderAgent. Jeśli dane logowania zostały zapisane, sprawdź, czy są preferowane.

private fun isPreferredThreadNetworkByBorderAgent(borderAgentInfo: BorderAgentInfo) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  var isPreferred = IsPreferredCredentialsResult.PREFERRED_CREDENTIALS_NOT_FOUND
  var borderAgentCredentials: ThreadNetworkCredentials?
  val taskByBorderAgent = ThreadNetwork.getClient(this)
  taskByBorderAgent
      .getCredentialsByBorderAgent(threadBorderAgent)
      .addOnSuccessListener { result: ThreadNetworkCredentialsResult ->
        borderAgentCredentials = result.credentials
        result.credentials?.let {
          taskByBorderAgent.isPreferredCredentials(it).addOnSuccessListener { result ->
            isPreferred = result
          }
        }
      }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Dane logowania do sieci Thread według rozszerzonego identyfikatora PAN

Podobnie jak w przypadku getPreferredCredentials, możesz też poprosić użytkownika o dane logowania z rozszerzonego identyfikatora PAN urządzenia TBR. getCredentialsByExtendedPanId zwraca IntentSender, a wynik aktywności zawiera obiekt ThreadNetworkCredentials, gdy użytkownik zatwierdzi działanie.

private fun getCredentialsByExtPanId(borderAgentInfo: BorderAgentInfo) {
  ThreadNetwork.getClient(this)
    .getCredentialsByExtendedPanId(borderAgentInfo.extPanId)
    .addOnSuccessListener { intentSenderResult ->
      intentSenderResult.intentSender?.let {
        preferredCredentialsLauncher.launch(IntentSenderRequest.Builder(it).build())
      }
        ?: Log.d("debug", "No credentials found.")
    }
    .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Usuwanie danych logowania

Gdy urządzenie border router zostanie usunięte z domu lub przywrócone do ustawień fabrycznych, musisz usunąć jego sieć Thread z usług Google Play.

private fun removeCredentials(borderAgentInfo: BorderAgentInfo) {

  val threadBorderAgent = ThreadBorderAgent.newBuilder(borderAgentInfo.borderAgentId).build()
  Log.d("debug", "border router id:" + threadBorderAgent.id)

  ThreadNetwork.getClient(this)
      .removeCredentials(threadBorderAgent)
      .addOnSuccessListener { Log.d("debug", "Credentials removed.") }
      .addOnFailureListener { e: Exception -> Log.d(TAG, "ERROR: [${e}]") }
}

Zasoby

Więcej informacji o pakiecie Thread Network SDK znajdziesz w dokumentacji API.