SDK לרשת Thread for Android

ב-Thread Network SDK יש פונקציונליות דומה למחזיק מפתחות דיגיטלי, ולכן לאפליקציות ל-Android יש אפשרות לשתף את פרטי הכניסה של פרוטוקול Thread עם Google Play Services. כך ניתן להגדיר בכל מכשיר כל Thread מתוך כל סביבה ביתית חכמה, בלי לחשוף ישירות את פרטי הכניסה ופרטי המשתמש.

באמצעות כמה קריאות ל-API אפשר:

  1. ניתן לבקש פרטי כניסה מועדפים לרשת השרשורים מ-Google Play Services.
  2. הגדרת נתבי גבול חדשים והוספת פרטי הכניסה של פרוטוקול Thread לשירותי Google Play.
  3. אם כבר יש לכם נתבי גבול בתוך השדה, תוכלו לבדוק אם נתבי הגבולות נמצאים ברשת המועדפת ולהעביר אותם, במקרה הצורך.

יש כמה מסלולים להמרת משתמשים ולמפתחים. ריכזנו במדריך הזה את רוב המאפיינים האלה, יחד עם תכונות חשובות נוספות ושימוש מומלץ.

מונחי מפתח ומושגים מרכזיים ב-API

לפני שמתחילים, חשוב להבין את המונחים הבאים:

  • פרטי הכניסה של פרוטוקול Thread: blob בינארי של Thread TLV, שמקודד את שם הרשת של Thread, מפתח הרשת ונכסים אחרים שנדרשים למכשיר של Thread כדי להצטרף לרשת נתונה של Thread.

  • Credentials Thread Network Credentials: פרטי הכניסה של פרוטוקול Thread שנבחרו אוטומטית, שאפשר לשתף עם אפליקציות של ספקים שונים באמצעות ה-API getPreferredCredentials.

  • מזהה סוכן גבול: מזהה ייחודי גלובלי של 16 בייט למכשיר נתב גבולות. המזהה הזה נוצר ומנוהל על ידי ספקים של נתבי גבול.

  • אפליקציית הגדרת נתב גבולות: האפליקציה ל-Android שמגדירים מכשירים חדשים של Thread Border Router ומוסיפה את פרטי הכניסה לרשת Thread לשירותי Google Play. האפליקציה שלכם היא הבעלים המוסמכים של פרטי הכניסה שנוספו, והם יכולים לגשת אליהם.

הרבה מממשקי ה-API של רשת Thread מחזירים משימה שמסתיימת באופן אסינכרוני. אפשר להשתמש ב-addOnSuccessListener וב-addOnFailureListener כדי לרשום קריאות חוזרות (callback) לקבלת התוצאה. למידע נוסף, עיינו במסמכי התיעוד בנושא משימה.

הבעלות והתחזוקה של פרטי הכניסה

לאפליקציה שמוסיפה את פרטי הכניסה של Thread מוגדרת כבעלים של פרטי הכניסה, ויש לה הרשאות מלאות לגישה לפרטי הכניסה. אם תנסו לגשת לפרטי כניסה שנוספו על ידי אפליקציות אחרות, תופיע הודעת השגיאה PERMISSION_DENIED.

כבעלים של האפליקציה, מומלץ לשמור על העדכניות של פרטי הכניסה המאוחסנים בשירותי Google Play כשרשת ה-Thread Border Router מתעדכנת. כלומר, צריך להוסיף את פרטי הכניסה כשצריך, לעדכן את פרטי הכניסה כשפרטי הכניסה לרשת של Thread של נתב הגבולות משתנים ולהסיר את הנתב כשמסירים את נתב הגבולות או לאפס להגדרות המקוריות.

זיהוי סוכן גבול

יש לשמור את פרטי הכניסה עם מזהה סוכן גבול. תצטרכו לוודא שהאפליקציה להגדרת הנתב של גבולות הגבולות מצליחה לזהות את המזהים של גבולות הגבולות של נתבי הגבולות של השרשורים.

נתבי גבול של Thread חייבים להשתמש ב-mDNS כדי לפרסם מידע על הרשת של Thread, כולל שם הרשת, מזהה החלונית המורחבת ומזהה סוכן הגבול. הערכים התואמים ב-txt למאפיינים האלה הם nn, xp ו-id, בהתאמה.

עבור רשתות עם נתבי גבולות של Google, שירותי Google Play מקבלים אוטומטית את פרטי הכניסה של רשת Google Thread לשימוש.

שילוב ה-SDK באפליקציה ל-Android

כדי להתחיל, צריך לבצע את השלבים הבאים:

  1. פועלים לפי ההוראות במאמר הגדרת Google Play Services.

  2. מוסיפים את התלות ב-Google Play Services לקובץ build.gradle:

    implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0'
    
  3. אופציונלי: צריך להגדיר סיווג נתונים ב-BorderAgent לאחסון מידע על נתב גבולות. נשתמש בנתונים האלה במדריך הזה:

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

עכשיו נעבור על השלבים המומלצים להוספה ולניהול של פרטי הכניסה המועדפים.

הגדרות חדשות של נתב גבולות

לפני שיוצרים רשת חדשה של נתבי גבולות חדשים, חשוב לנסות תחילה להשתמש בפרטי הכניסה המועדפים לרשת. כך אפשר להבטיח שמכשירי Thread מחוברים לרשת Thread אחת כשזה אפשרי.

קריאה ל-getPreferredCredentials מפעילה פעילות שבה המשתמשים מתבקשים לאשר את בקשת הרשת. אם פרטי הכניסה לרשת אוחסנו במפתחות הדיגיטלי של Thread SDK, פרטי הכניסה יוחזרו לאפליקציה.

בקשת פרטי כניסה

כדי לבקש מהמשתמש פרטי כניסה מועדפים:

  1. מצהירים על ActivityLauncher:

    private lateinit var preferredCredentialsLauncher: ActivityResultLauncher<IntentSenderRequest>
    
  2. יש לטפל בתוצאת הפעילות, המוחזרת בתור 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. צריך להתקשר אל preferredCredentials ולהפעיל את הפעילות:

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

יצירת רשת חדשה של Thread

אם אין פרטי כניסה מועדפים לרשת Thread שזמינים ברשת של המשתמש, אפשר להשתמש ב-addCredentials API כדי להוסיף פרטי כניסה לשירותי Google Play. כדי לעשות זאת, צריך ליצור ThreadBorderAgent וגם לספק אובייקט ThreadNetworkCredentials.

כדי ליצור רשת אקראית, התקשר אל newRandomizeBuilder:

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

כדי לציין את שם רשת השרשורים:

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

הוספת פרטי כניסה

כדי להפוך את פרטי הכניסה של פרוטוקול Thread לזמינים לספקי Thread אחרים, אנחנו צריכים להוסיף אותם לשירותי Google Play. כדי שנוכל להוסיף את פרטי הכניסה החדשים, אנחנו צריכים גם לדעת לאיזה מכשיר של נתב הגבולות שייך רשת השרשורים.

בדוגמה הזו ניצור ThreadBorderAgent ממזהה סוכן גבול, ונעביר את פרטי הכניסה החדשים לרשת השרשורים שיצרתם:

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

זיהוי נתבי גבול בתוך האזור והעברה שלהם

אם יש לכם כרגע נתבי גבול בתוך השדה, תוכלו להשתמש ב-isPreferredCredentials כדי לבדוק אם נתבי הגבולות שלכם שייכים לרשת המועדפת. ממשק ה-API הזה לא מבקש הרשאה מהמשתמש, ובודק את פרטי הכניסה של נתב הגבולות לעומת מה שנשמר בשירותי Google Play.

isPreferredCredentails מחזירה 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 במספר דרכים. בשלבים הבאים נעבור על האפשרויות האלה.

שרשור פרטי כניסה של רשת לפי מערך נתונים תפעולי

במקרים מסוימים, נתב הגבולות כבר מוגדר באמצעות רשת Thread, ואתם רוצים להוסיף את הרשת הזו של Thread לשירותי Google Play כדי לשתף אותה עם ספקים אחרים. אתם יכולים ליצור מכונה מסוג ThreadNetworkCredential מרשימת ה-TLV פעיל/ה של מערך הנתונים התפעולי של Thread:

  1. ממירים את מערך הנתונים התפעולי ל-ByteArray. למשל:

    val activeDataset =
          "0e080000000000010000000300000f35060004001fffe0020833333333...".dsToByteArray()
    
    fun String.dsToByteArray(): ByteArray {
      return chunked(2).map { it.toInt(16).toByte() }.toByteArray()
    }
    
  2. יש להשתמש ב-fromActiveOperationalDataset ליצירת ThreadNetworkCredentials. כשהתהליך יסתיים, תהיה לך אפשרות לקבל את שם הרשת של הערוץ, הערוץ ומידע נוסף על הרשת. רשימת הנכסים המלאה מופיעה במאמר ThreadNetworkCredentials.

    val threadNetworkCredentials =
        ThreadNetworkCredentials.fromActiveOperationalDataset(activeDataset)
    Log.d(
        "threadNetworkCredentials",
        threadNetworkCredentials.channel.toString() + " - " + threadNetworkCredentials.networkName)
    
  3. מפעילים את isPreferredCredentials API ועוברים את 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}]") }
    

פרטי הכניסה של פרוטוקול Thread by Border Agent

מזהה סוכן גבול מזהה באופן ייחודי מכשיר נתב גבול. כדי להשתמש ב-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}]") }
}

פרטי הכניסה של הרשת בשרשור לפי מזהה הזזה מורחב

בדומה ל-getPreferredCredentials, תוכלו גם לבקש מהמשתמש פרטי כניסה ממזהה ההרחבה המורחב של נתב הגבולות. הפונקציה getCredentialsByExtendedPanId מחזירה IntentSender, ותוצאת הפעילות מכילה אובייקט 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}]") }
}

הסרת פרטי הכניסה

כשמסירים את המכשיר של נתב הגבולות מהבית או מהאיפוס להגדרות המקוריות, צריך להסיר את רשת השרשורים משירותי 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.