Thread Network SDK สำหรับ Android

Thread Network SDK มีฟังก์ชันการทำงานที่คล้ายกับพวงกุญแจดิจิทัล ซึ่งช่วยให้แอป Android แชร์ข้อมูลเข้าสู่ระบบของเครือข่าย Thread กับบริการ Google Play ได้ ซึ่งจะช่วยให้แอปของคุณตั้งค่าอุปกรณ์ Thread จากระบบนิเวศสมาร์ทโฮมใดก็ได้ โดยไม่ต้องเปิดเผยข้อมูลเข้าสู่ระบบและข้อมูลผู้ใช้โดยตรง

การเรียก API เพียงไม่กี่ครั้งจะช่วยให้คุณทำสิ่งต่อไปนี้ได้

  1. ขอข้อมูลเข้าสู่ระบบเครือข่าย Thread ที่ต้องการจากบริการ Google Play
  2. ตั้งค่า Thread Border Router (TBR) ใหม่และเพิ่มข้อมูลเข้าสู่ระบบเครือข่าย Thread ลงในบริการ Google Play
  3. หากคุณมี TBR ในฟิลด์อยู่แล้ว คุณสามารถตรวจสอบว่า TBR อยู่ในเครือข่ายที่ต้องการหรือไม่ และย้ายข้อมูลหากจำเป็น

มีเส้นทางของผู้ใช้และนักพัฒนาแอปหลายเส้นทางที่ควรพิจารณา เราจะอธิบายฟีเจอร์ส่วนใหญ่ในคู่มือนี้ พร้อมกับฟีเจอร์หลักอื่นๆ และการใช้งานที่แนะนำ

คำศัพท์สำคัญและแนวคิดเกี่ยวกับ API

ก่อนเริ่มต้น คุณควรทำความเข้าใจคำศัพท์ต่อไปนี้

  • ข้อมูลเข้าสู่ระบบของเครือข่าย Thread: Binary Blob ของ Thread TLV ที่เข้ารหัสชื่อเครือข่าย Thread, คีย์เครือข่าย และพร็อพเพอร์ตี้อื่นๆ ที่อุปกรณ์ Thread ต้องใช้เพื่อเข้าร่วมเครือข่าย Thread ที่ระบุ

  • ข้อมูลเข้าสู่ระบบของเครือข่าย Thread ที่ต้องการ: ข้อมูลเข้าสู่ระบบของเครือข่าย Thread ที่เลือกโดยอัตโนมัติซึ่งสามารถแชร์กับแอปของผู้ให้บริการรายต่างๆ โดยใช้ getPreferredCredentials API

  • รหัส Border Agent: รหัสที่ไม่ซ้ำกันขนาด 16 ไบต์ทั่วโลกสำหรับอุปกรณ์ TBR รหัสนี้สร้างและจัดการโดยผู้ให้บริการ border router ราย

  • แอปการตั้งค่า TBR: นี่คือแอป Android ที่ตั้งค่าอุปกรณ์ TBR เครื่องใหม่และเพิ่มข้อมูลเข้าสู่ระบบเครือข่าย Thread ลงในบริการ Google Play แอปของคุณเป็นเจ้าของที่เชื่อถือได้ของข้อมูลเข้าสู่ระบบที่เพิ่มเข้ามาและมีสิทธิ์เข้าถึงข้อมูลดังกล่าว

Thread Network API จำนวนมากจะแสดงผล Task ที่ทำงานแบบไม่พร้อมกัน คุณสามารถใช้ addOnSuccessListener และ addOnFailureListener เพื่อลงทะเบียน Callback สำหรับรับผลลัพธ์ ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบเกี่ยวกับ Task

การเป็นเจ้าของและการบำรุงรักษาข้อมูลเข้าสู่ระบบ

แอปที่เพิ่มข้อมูลเข้าสู่ระบบเครือข่าย Thread จะเป็นเจ้าของข้อมูลเข้าสู่ระบบ และมีสิทธิ์เข้าถึงข้อมูลเข้าสู่ระบบอย่างเต็มรูปแบบ หากพยายามเข้าถึงข้อมูลเข้าสู่ระบบที่เพิ่มโดยแอปอื่นๆ คุณจะได้รับข้อผิดพลาด PERMISSION_DENIED

ในฐานะเจ้าของแอป เราขอแนะนำให้คุณอัปเดตข้อมูลเข้าสู่ระบบที่จัดเก็บไว้ในบริการ Google Play ให้เป็นปัจจุบันเมื่อมีการอัปเดตเครือข่าย TBR ซึ่งหมายถึงการเพิ่มข้อมูลเข้าสู่ระบบเมื่อจำเป็น การอัปเดตข้อมูลเข้าสู่ระบบเมื่อข้อมูลเข้าสู่ระบบเครือข่าย Thread ของ border router มีการเปลี่ยนแปลง และการนำข้อมูลเข้าสู่ระบบออกเมื่อมีการนำ TBR ออกหรือรีเซ็ตเป็นค่าเริ่มต้น

การค้นหา Border Agent

ต้องบันทึกข้อมูลเข้าสู่ระบบพร้อมรหัส Border Agent คุณจะต้องตรวจสอบว่าแอปการตั้งค่า TBR สามารถระบุรหัส Border Agent ของ TBR ได้

TBR ต้องใช้ mDNS เพื่อกระจายข้อมูลเครือข่าย Thread ซึ่งรวมถึงชื่อเครือข่าย, Extended Pan ID และ Border Agent ID ค่า txt ที่สอดคล้องกันสำหรับแอตทริบิวต์เหล่านี้คือ nn, xp และ id ตามลำดับ

สำหรับเครือข่ายที่มี Google Thread Border Router (gTBR) บริการ Google Play จะรับข้อมูลเข้าสู่ระบบเครือข่าย Google Thread โดยอัตโนมัติเพื่อนำไปใช้

ผสานรวม SDK เข้ากับแอป Android

หากต้องการเริ่มต้นใช้งาน ให้ทำตามขั้นตอนต่อไปนี้

  1. ทำตามวิธีการที่ระบุไว้ในตั้งค่าบริการ Google Play

  2. เพิ่มทรัพยากร Dependency ของบริการ Google Play ลงในไฟล์ build.gradle ดังนี้

    implementation 'com.google.android.gms:play-services-threadnetwork:16.2.1'
    
  3. ไม่บังคับ: กำหนดคลาสข้อมูล 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 ใหม่

ก่อนสร้างเครือข่ายใหม่สำหรับ Border Router ใหม่ คุณควรลองใช้ข้อมูลเข้าสู่ระบบของเครือข่ายที่ต้องการก่อน ซึ่งจะช่วยให้อุปกรณ์ 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. หากคุณกำลังตั้งค่า 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}]") }
    }
    
  4. หาก Use Case ของคุณเกี่ยวข้องกับการตั้งค่าอุปกรณ์ที่ไม่ใช่ 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 ที่ใช้งานอยู่ในเครือข่าย Thread ของผู้ใช้ คุณสามารถใช้ addCredentials API เพื่อเพิ่มข้อมูลเข้าสู่ระบบลงในบริการ Google Play ได้ โดยคุณจะต้องสร้าง ThreadBorderAgent และระบุออบเจ็กต์ ThreadNetworkCredentials ด้วย

หากต้องการสร้างเครือข่ายแบบสุ่ม ให้เรียกใช้ newRandomizeBuilder ดังนี้

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

วิธีระบุชื่อเครือข่าย Thread

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

เพิ่มข้อมูลรับรอง

เราจำเป็นต้องเพิ่มข้อมูลเข้าสู่ระบบของเครือข่าย Thread ลงในบริการ Google Play เพื่อให้ผู้ให้บริการ Thread รายอื่นๆ สามารถใช้ข้อมูลเข้าสู่ระบบของเครือข่าย Thread ได้ ก่อนที่จะเพิ่มข้อมูลเข้าสู่ระบบใหม่ได้ เราต้องทราบก่อนว่าเครือข่าย Thread นี้เป็นของอุปกรณ์ TBR เครื่องใด

ในตัวอย่างนี้ เราจะสร้าง 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 ทำได้หลายวิธี ในขั้นตอนถัดไป เราจะอธิบายตัวเลือกเหล่านี้

ข้อมูลเข้าสู่ระบบของเครือข่าย Thread ตามชุดข้อมูลการทำงาน

ในบางกรณี TBR ของคุณอาจตั้งค่าด้วยเครือข่าย 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 เมื่อดำเนินการสำเร็จ คุณจะได้รับชื่อเครือข่าย Thread, ช่อง และข้อมูลเครือข่ายอื่นๆ ดูรายการพร็อพเพอร์ตี้ทั้งหมดได้ที่ 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 โดย Border Agent

รหัส Border Agent จะระบุอุปกรณ์ TBR โดยไม่ซ้ำกัน หากต้องการใช้ getCredentialsByBorderAgent API คุณจะต้องสร้างออบเจ็กต์ ThreadBorderAgent และส่งรหัส Border Agent ก่อน

เมื่อสร้างออบเจ็กต์ 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}]") }
}

ข้อมูลเข้าสู่ระบบของเครือข่าย Thread ตามรหัส PAN แบบขยาย

คุณยังสามารถแจ้งให้ผู้ใช้ป้อนข้อมูลเข้าสู่ระบบจากรหัส PAN แบบขยายของ TBR ได้เช่นเดียวกับ 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}]") }
}

นำข้อมูลเข้าสู่ระบบออก

เมื่อนำอุปกรณ์ 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