SDK сети Thread предоставляет функциональность, аналогичную цифровому брелоку, позволяя вашим приложениям для Android обмениваться учетными данными сети Thread с сервисами Google Play. Это позволяет вашим приложениям настраивать любое устройство Thread из любой экосистемы умного дома, не раскрывая напрямую учетные данные и пользовательские данные.
Всего несколькими вызовами API вы можете:
- Запросите у сервисов Google Play учетные данные сети Thread.
- Настройте новые Thread Border Router (TBR) и добавьте учетные данные вашей сети Thread в сервисы Google Play.
- Если у вас уже есть установленные на объекте блоки TBR , вы можете проверить, находятся ли ваши блоки TBR в предпочтительной сети, и при необходимости перенести их.
Существует несколько сценариев взаимодействия пользователя и разработчика, которые необходимо учитывать. В этом руководстве мы рассмотрим большинство из них, а также другие ключевые функции и рекомендации по их использованию.
Ключевые термины и концепции API
Прежде чем начать, полезно ознакомиться со следующими терминами:
Учетные данные сети потока: двоичный блок TLV-файлов потока, кодирующий имя сети потока, сетевой ключ и другие свойства, необходимые устройству потока для присоединения к заданной сети потока.
Предпочтительные сетевые учетные данные Thread: автоматически выбранные сетевые учетные данные Thread, которые можно передавать приложениям разных поставщиков с помощью API
getPreferredCredentials.Идентификатор пограничного агента: 16-байтовый глобально уникальный идентификатор для устройства TBR . Этот идентификатор создается и управляется производителями border router .
Приложение для настройки TBR : это ваше приложение для Android, которое настраивает новые устройства TBR и добавляет учетные данные сети Thread в сервисы Google Play. Ваше приложение является полноправным владельцем добавленных учетных данных и имеет к ним доступ.
Многие API сети потоков возвращают задачу , которая завершается асинхронно. Вы можете использовать addOnSuccessListener и addOnFailureListener для регистрации обратных вызовов для получения результата. Для получения дополнительной информации обратитесь к документации по задачам .
Владение и поддержание учетных данных
Приложение, добавившее учетные данные сети Thread, становится владельцем этих учетных данных и получает полные права доступа к ним. Если вы попытаетесь получить доступ к учетным данным, добавленным другими приложениями, вы получите ошибку PERMISSION_DENIED .
Владельцам приложений рекомендуется обновлять учетные данные, хранящиеся в сервисах Google Play, при обновлении сети TBR . Это означает добавление учетных данных по мере необходимости, обновление учетных данных при изменении учетных данных сети Thread на border router и удаление учетных данных при удалении или сбросе настроек TBR до заводских.
Обнаружение пограничного агента
Учетные данные необходимо сохранить с идентификатором пограничного агента. Вам нужно убедиться, что ваше приложение для настройки TBR может определять идентификаторы пограничных агентов для ваших TBR .
Для передачи информации о сети Thread, включая имя сети, расширенный идентификатор Pan и идентификатор пограничного агента, TBR должен использовать mDNS. Соответствующие txt значения для этих атрибутов — nn , xp и id соответственно.
В сетях, использующих Google Thread Border Router (gTBR) , сервисы Google Play автоматически получают учетные данные сети Google Thread для использования.
Интегрируйте SDK в ваше Android-приложение.
Для начала выполните следующие шаги:
Следуйте инструкциям, приведенным в разделе «Настройка сервисов Google Play» .
Добавьте зависимость от сервисов Google Play в файл
build.gradle:implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'Необязательно: Определите класс данных
BorderAgentдля хранения информации TBR . Мы будем использовать эти данные на протяжении всего руководства:data class BorderAgentInfo( // Network Name max 16 len val networkName: String = "", val extPanId: ByteArray = ByteArray(16), val borderAgentId: ByteArray = ByteArray(16), ... )
Далее мы рассмотрим рекомендуемые шаги для добавления и управления предпочтительными учетными данными.
Новые настройки маршрутизатора Thread Border Router
Прежде чем создавать новую сеть для новых пограничных маршрутизаторов, важно сначала попробовать использовать предпочтительные сетевые учетные данные. Это гарантирует, что устройства Thread будут подключены к одной сети Thread, если это возможно.
Вызов функции getPreferredCredentials запускает Activity, предлагая пользователям разрешить сетевой запрос. Если сетевые учетные данные были сохранены в цифровой связке ключей Thread SDK, эти учетные данные возвращаются в ваше приложение.
Запросить учетные данные
Чтобы запросить у пользователя предпочтительные учетные данные:
Объявите
ActivityLauncher:private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>Обработайте результат выполнения Activity, возвращаемый в виде
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.") } }При настройке нового TBR рекомендуется вызвать
preferredCredentialsи запустить соответствующую активность. Этот вызов гарантирует, что ваш новый TBR будет использовать те же учетные данные, которые уже сохранены в телефоне в качестве предпочтительных , способствуя объединению различных TBR в одной сети.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}]") } }Если ваша задача связана с настройкой устройств, не использующих TBR, например, нового конечного устройства Matter-over-Thread, рекомендуется использовать API
allActiveCredentialsдля получения учетных данных. Этот вызов просканирует локальную сеть на наличие TBR и, следовательно, не вернет учетные данные, недоступные для существующего локального 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 }
Создайте новую сеть потоков.
Если в сети Thread пользователя отсутствуют как предпочтительные учетные данные Thread, так и активные учетные данные Thread, то для добавления учетных данных в сервисы Google Play можно использовать API addCredentials . Для этого необходимо создать объект ThreadBorderAgent и предоставить объект ThreadNetworkCredentials .
Для создания случайной нейронной сети вызовите метод newRandomizeBuilder :
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder().build()
Чтобы указать сетевое имя потока:
val threadCredentials = ThreadNetworkCredentials.newRandomizedBuilder()
.setNetworkName("ThreadNetworkSDK")
.build()
Добавить учетные данные
Чтобы сделать ваши учетные данные сети Thread доступными для других поставщиков Thread, нам необходимо добавить их в сервисы Google Play. Прежде чем добавить новые учетные данные, нам также необходимо знать, к какому устройству TBR относится эта сеть Thread.
В этом примере мы создадим объект ThreadBorderAgent на основе идентификатора Border Agent и передадим новые сетевые учетные данные 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}]") }
}
Обнаружение и миграция border router в полевых условиях.
Если у вас есть border router , установленные на местах, вы можете использовать isPreferredCredentials чтобы определить, принадлежат ли ваши border router к предпочтительной сети. Этот API не запрашивает у пользователя разрешения и проверяет учетные данные border router на соответствие данным, хранящимся в сервисах Google Play.
Функция isPreferredCredentials возвращает 0 если совпадение не найдено, и 1 если найдено, в виде Int типа данных. Вы можете использовать IsPreferredCredentialsResult для проверки результатов.
public @interface IsPreferredCredentialsResult {
int PREFERRED_CREDENTIALS_NOT_FOUND = -1;
int PREFERRED_CREDENTIALS_NOT_MATCHED = 0;
int PREFERRED_CREDENTIALS_MATCHED = 1;
}
Для использования isPreferredCredentials сначала необходимо создать объект ThreadNetworkCredentials . Существует несколько способов создания экземпляра ThreadNetworkCredentials . На следующих шагах мы рассмотрим эти варианты.
Учетные данные сети потока по оперативному набору данных
В некоторых случаях ваш TBR уже настроен с использованием сети Thread, и вы хотите добавить эту сеть Thread в Google Play Services, чтобы поделиться ею с другими поставщиками. Вы можете создать экземпляр ThreadNetworkCredential из списка TLV активных операционных данных Thread:
Преобразуйте оперативный набор данных в
ByteArray. Например:val activeDataset = "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()fun String.dsToByteArray(): ByteArray { return chunked(2).map { it.toInt(16).toByte() }.toByteArray() }Используйте
fromActiveOperationalDatasetдля создания объекта `ThreadNetworkCredentials. В случае успеха вы сможете получить имя сети потока, канал и другую информацию о сети. Полный список свойств см. в разделе ` ThreadNetworkCredentials` .val threadNetworkCredentials = ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset) Log.d( "threadNetworkCredentials", threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)Вызовите API-функцию
isPreferredCredentialsи передайте ей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}]") }
Получение сетевых учетных данных через Border Agent.
Идентификатор пограничного агента однозначно идентифицирует устройство TBR . Для использования API getCredentialsByBorderAgent сначала необходимо создать объект ThreadBorderAgent и передать в него идентификатор пограничного агента.
После создания объекта ThreadBorderAgent вызовите метод getCredentialsByBorderAgent . Если учетные данные были сохранены, проверьте, являются ли они предпочтительными.
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}]") }
}
Учетные данные сети потока по расширенному идентификатору Pan ID
Аналогично getPreferredCredentials , вы также можете запросить у пользователя учетные данные из расширенного идентификатора панели TBR . Метод getCredentialsByExtendedPanId возвращает объект IntentSender , а результат Activity содержит объект ThreadNetworkCredentials после подтверждения пользователем.
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}]") }
}
Удалить учетные данные
Если ваш border router был удален из домашней сети или сброшен до заводских настроек, вам необходимо удалить его сеть Thread из сервисов 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}]") }
}
Ресурсы
Для получения более подробной информации о Thread Network SDK обратитесь к справочнику API .