Pakiet SDK Thread Network na Androida

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

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

  1. Poproś o preferowanie danych logowania do sieci typu Thread przy użyciu Usług Google Play.
  2. Skonfiguruj nowe routery graniczne i dodaj dane logowania do sieci typu Thread do Usług Google Play.
  3. Jeśli masz już routery graniczne, możesz sprawdzić, czy routery graniczne znajdują się w preferowanej sieci, i w razie potrzeby je przenieść.

Do wyboru masz kilka ścieżek użytkownika i programistów. Większość z nich omówimy w tym przewodniku, razem z innymi ważnymi funkcjami i zalecanymi zastosowaniami.

Terminologia i podstawowe pojęcia związane z interfejsem API

Zanim zaczniesz, przeczytaj te terminy:

  • Dane logowania do sieci typu Thread: binarny obiekt blob TLV z kodem, który koduje nazwę sieci, klucz sieciowy i inne właściwości wymagane przez urządzenie w Thread, aby można było dołączyć do danej sieci Thread.

  • Preferowane dane logowania do sieci typu Thread: automatycznie wybierane dane logowania do sieci typu Thread, które mogą być udostępniane aplikacjom różnych dostawców za pomocą interfejsu API getPreferredCredentials.

  • Identyfikator agenta granicznego: niepowtarzalny na całym świecie 16-bajtowy identyfikator urządzenia routera granicznego wątku. Ten identyfikator jest tworzony i zarządzany przez dostawców routerów granicznych.

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

Wiele interfejsów Thread Network API zwraca zadanie wykonywane asynchronicznie. Za pomocą wywołań addOnSuccessListener i addOnFailureListener możesz rejestrować wywołania zwrotne w celu otrzymania wyniku. Więcej informacji znajdziesz w dokumentacji zadań.

Własność i konserwacja danych logowania

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

Jako właściciel aplikacji zalecamy aktualizowanie danych logowania w Usługach Google Play wraz z aktualizacją sieci routera granicy Thread. Oznacza to dodawanie danych logowania, gdy jest to wymagane, aktualizowanie danych logowania w przypadku zmiany danych logowania w sieci routera granicznego oraz usuwanie danych logowania po usunięciu routera granicznego wątku lub przywróceniu ustawień fabrycznych.

Wykrywanie agenta granicznego

Dane logowania muszą być zapisane z identyfikatorem agenta granicznego. Musisz sprawdzić, czy aplikacja do konfigurowania granic węzłów w aplikacji Thread jest w stanie określić identyfikatory agentów granic Twoich routerów granicznych Thread.

Routery granicy wątków muszą używać mDNS do reklamowania informacji o sieci typu Thread, w tym nazwy sieci, identyfikatora rozszerzonego pana i identyfikatora agenta granicznego. Odpowiadające im wartości txt w przypadku tych atrybutów to odpowiednio nn, xp i id.

W przypadku sieci z routerami granicznymi Google usługi Google Play automatycznie pobierają dane logowania do sieci typu Google Thread.

Zintegruj pakiet 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.0.0'
    
  3. Opcjonalnie: określ klasę danych BorderAgent do przechowywania informacji o routerze granicznym. Tych danych użyjemy w tym przewodniku:

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

W dalszej kolejności omówimy zalecane dodawanie danych logowania i zarządzanie nimi.

Nowe konfiguracje routera granicznego

Zanim utworzysz nową sieć dla nowych routerów granicznych, spróbuj najpierw użyć preferowanych danych logowania do sieci. Dzięki temu urządzenia z wątkami są w miarę możliwości połączone z pojedynczą siecią.

Wywołanie getPreferredCredentials uruchamia aktywność, zachęcającą użytkowników do zaakceptowania żądań sieciowych. Jeśli dane logowania do sieci zostały zapisane w cyfrowym pęku kluczy pakietu Thread SDK, dane logowania zostaną zwrócone do Twojej aplikacji.

Poproś o dane logowania

Aby wyświetlić użytkownikowi prośbę o podanie preferowanych danych logowania:

  1. Zadeklaruj ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. Przetwórz wynik działania 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. Zadzwoń do aplikacji preferredCredentials i uruchom aktywność:

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

Utwórz nową sieć Thread

Jeśli w sieci użytkownika nie są dostępne preferowane dane logowania do sieci typu Thread, do dodawania usług do Usług Google Play możesz użyć interfejsu API addCredentials. Aby to zrobić, musisz utworzyć ThreadBorderAgent i podać obiekt ThreadNetworkCredentials.

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

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

Aby określić nazwę sieci typu Thread:

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

Dodaj dane logowania

Aby udostępnić dane logowania do sieci typu Thread innym dostawcom, musisz dodać je do Usług Google Play. Zanim dodamy nowe dane logowania, musimy wiedzieć, do którego urządzenia routera granicznego należy sieć.

W tym przykładzie utworzymy ThreadBorderAgent z identyfikatora agenta granicznego i przekażemy nowe dane logowania do sieci typu 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 routerów granicznych w terenie

Jeśli masz już routery graniczne, możesz użyć właściwości isPreferredCredentials, aby określić, czy routery graniczne należą do preferowanej sieci. Ten interfejs API nie prosi użytkownika o pozwolenie i sprawdza, czy dane logowania routera nie są przechowywane w Usługach Google Play.

isPreferredCredentails zwraca 0 w przypadku niedopasowanego dopasowania, a 1 dla pasujących w postaci typu danych Int. Wyniki możesz sprawdzić w IsPreferredCredentialsResult.

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

Aby użyć właściwości isPreferredCredentials, musisz najpierw utworzyć obiekt ThreadNetworkCredentials. Wystąpienie ThreadNetworkCredentials można utworzyć na kilka sposobów. W kolejnych krokach omówimy te opcje.

Dane logowania do sieci typu Thread według operacyjnego zbioru danych

W niektórych przypadkach router z wątkami Thread ma już skonfigurowaną sieć typu Thread i chcesz ją dodać do usług Google Play, by udostępnić ją innym dostawcom. Instancję ThreadNetworkCredential możesz utworzyć z nieprzetworzonej listy TLV aktywnych wątków:

  1. Przekształć działający zbiór danych w element 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. Gdy to zrobisz, uzyskasz dostęp do nazwy sieci, kanału i innych informacji 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 isPreferredCredentials API 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 typu Thread według agenta granicznego

Identyfikator agenta granicznego identyfikuje urządzenie routera granicznego. Aby korzystać z interfejsu API getCredentialsByBorderAgent, musisz najpierw utworzyć obiekt ThreadBorderAgent i przekazać identyfikator agenta granicznego.

Po utworzeniu obiektu ThreadBorderAgent wywołaj funkcję getCredentialsByBorderAgent. Jeśli dane logowania zostały zapisane, sprawdź, czy są one 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 typu Thread według rozszerzonego numeru PAN

Podobnie jak w przypadku getPreferredCredentials, możesz prosić użytkownika o podanie danych logowania z rozszerzonego identyfikatora granicy routera granicznego. getCredentialsByExtendedPanId zwraca wartość IntentSender, a wynik działania zawiera obiekt ThreadNetworkCredentials, gdy użytkownik ją zatwierdzi.

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

Usuń dane logowania

Gdy urządzenie routera granicznego zostanie usunięte z domu lub urządzenia przywróconego do ustawień fabrycznych, trzeba będzie usunąć z jego sieci sieć Thread.

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 SDK Thread Network znajdziesz w przewodniku po interfejsie API.