1. Başlamadan önce
Thread Kenarlık Yönlendirici (TBR) codelab'inde, Raspberry Pi'ye dayalı bir İş Parçacığı Yönlendiricisi oluşturma konusunu göstereceğiz. Bu codelab'de
- Thread ve kablosuz/Ethernet ağları arasında Çift Yönlü IP bağlantısı oluşturun.
- mDNS (kablosuz/Ethernet bağlantısında) ve SRP (Thread ağında) aracılığıyla çift yönlü hizmet keşfi sağlayın.
Bu codelab'de, kendi sınır yönlendiricinizin ve uygulamanızın, tek bir Thread Ağı oluşturmak için Google API'leriyle nasıl etkileşimde bulunabileceği ele alınmaktadır. Thread kimlik bilgilerinin birleştirilmesi, ağ dayanıklılığını artırdığı ve Thread'dan yararlanan uygulamalarla kullanıcı etkileşimlerini basitleştirdiği için önemlidir.
Ön koşullar
- OTBR Codelab'i tamamlayın
- Linux, Android/Kotlin ve Thread ağı hakkında temel düzeyde bilgi
Neler öğreneceksiniz?
- Kimlik bilgisi kümelerini almak ve ayarlamak için Thread Share API'leri kullanma
- Google'ın ağıyla aynı kimlik bilgileriyle kendi OpenThread Sınır Yönlendiricinizi ayarlama
Gerekenler
- Raspberry Pi 4 kart veya Open Thread Border Router (OTBR) çalıştıran başka bir Linux tabanlı kart
- Radyo Ortak İşlemcisi (RCP) olarak IEEE 802.15.4 bağlantısı sağlayan kurul. OpenThread GitHub sayfasında farklı SoC tedarikçi firmalarının depolarının listesini ve talimatlarını görün
2. HTTP hizmetini kurma
İhtiyacımız olan ilk yapı taşı, Etkin Kimlik Bilgilerini okumamızı ve Beklemedeki Kimlik Bilgilerini OTBR'nize yazmamızı sağlayan bir arayüzdür. TBR oluştururken burada iki örnekle gösterildiği gibi kendi özel mekanizmalarınızı kullanın. İlk seçenek OTBR aracısıyla DBUS üzerinden yerel olarak nasıl arayüz kurulacağını gösterirken, ikinci seçenek OTBR üzerinde oluşturulabilen Rest API'yi kullanır.
İki yöntem de güvenli değildir ve üretim ortamında olduğu gibi kullanılmamalıdır. Ancak tedarikçi firma, yöntemi bir üretim ortamında kullanmak için her iki yöntem etrafında da şifreleme oluşturabilir veya kendi izleme hizmetinizi, geri dönüş HTTP ya da doğal olarak yerel DBUS çağrıları gönderecek şekilde genişletebilir.
1. seçenek: Python Komut Dosyası üzerinde DBUS ve HTTP API
Bu adım, kimlik bilgilerini okumak ve ayarlamak için iki uç noktayı kullanıma sunan, daha sonra DBUS komutlarını çağıran sade bir HTTP hizmeti oluşturur.
OTBR'niz olarak kullanılacak RPi'de Python 3 bağımlılıklarını yükleyin:
$ pip install dbus-python shlex json
Komut dosyasını şu şekilde çalıştırın:
$ sudo python credentials_server.py 8081 serving at port 8081
Örnek, 8081 numaralı bağlantı noktasında bir HTTP sunucusu oluşturur ve Thread kimlik bilgilerini almak için GET isteğini ya da Thread kimlik bilgilerini ayarlamak için POST isteğini kök yolunda dinler. Yük her zaman TLV ile JSON yapısıdır.
Aşağıdaki PUT isteği, /node/dataset/pending
yolunu kullanarak yeni Beklemedeki İş Parçacığı Kimlik Bilgilerini OTBR'ye ayarlar. Bu durumda, bekleyen kimlik bilgileri 10 saniye içinde uygulanır:
PUT /node/dataset/pending Host: <IP>:8081 ContentType: "application/json" acceptMimeType: "application/json" ... { "ActiveDataset": "<TLV encoded new Thread Dataset>" "PendingTimestamp": { "Seconds": <Unix timestamp in seconds>, "Ticks": 0, "Authoritative": false }, "Delay": 10000 // in milliseconds }
/node/dataset/active
için yapılan GET isteği, geçerli olarak etkin olan kimlik bilgilerini getirir.
GET /node/dataset/active Host: <IP>:8081 ContentType = "application/json" acceptMimeType = "text/plain" ... <TLV encoded Thread Dataset>
Komut dosyası, io.openthread.BorderRouter.wpan0
veri yolu yolu /io/openthread/BorderRouter/wpan0
nesne yoluna DBUS R/W komutlarını çağırıyor
# D-BUS interface def call_dbus_method(interface, method_name, *arguments): bus = dbus.SystemBus() obj = bus.get_object('io.openthread.BorderRouter.wpan0', '/io/openthread/BorderRouter/wpan0') iface = dbus.Interface(obj, interface) method = getattr(iface, method_name) res = method(*arguments) return res def get_dbus_property(property_name): return call_dbus_method('org.freedesktop.DBus.Properties', 'Get', 'io.openthread.BorderRouter', property_name) def set_dbus_property(property_name, property_value): return call_dbus_method('org.freedesktop.DBus.Properties', 'Set', 'io.openthread.BorderRouter', property_name, property_value)
DBUS, yeteneklerinin iç gözleme alınmasını sağlıyor. Bu işlemi aşağıdaki şekilde yapabilirsiniz:
$ sudo dbus-send --system --dest=io.openthread.BorderRouter.wpan0 \ --type=method_call --print-reply /io/openthread/BorderRouter/wpan0 \ org.freedesktop.DBus.Introspectable.Introspect
Burada belirtilen desteklenen özellikleri de kontrol edebilirsiniz.
2. seçenek: OTBR Aracısı yerel HTTP Rest API
OpenThread Sınır Yönlendirici, varsayılan olarak REST_API=1
işaretiyle oluşturulur ve REST API'yi etkinleştirir. Önceki bir codelab'den oluşturulan derlemeniz REST API'yi etkinleştirmediyse RPi'nizde aşağıdaki işaretle OTBR derlediğinizden emin olun:
$ REST_API=1 INFRA_IF_NAME=wlan0 ./script/setup
Bir OTBR aracısı şu çalıştırılarak yeniden başlatılabilir:
$ sudo systemctl restart otbr-agent.service
Aracı, 8081 numaralı bağlantı noktasında bir HTTP sunucusu başlatır. Bu sunucu, bir kullanıcının veya izleme programının OTBR'de birçok görevi gerçekleştirmesine olanak tanır (burada açıklanmıştır). İçeriğini incelemek için tarayıcınızı (curl
veya wget
) kullanabilirsiniz. Desteklenen birçok yol arasında, /node/dataset/active
üzerinde GET
fiili ve /node/dataset/pending
'de PUT
fiilinin yer aldığı, yukarıda açıklanan kullanım alanları da bulunmaktadır.
3. Android'de Kimlik Bilgisi Çerçevesi'ni ayarlama
Tercih Edilen Kimlik Bilgileri
Android'de Google Play Hizmetleri, ağınızdaki tüm TBR'ler için kimlik bilgilerinin kaydedilmesine izin verir ve bunu bekler. Her biri kendi Sınır Yönlendirici Aracısı Kimliği (BAID) ile tanımlanır. Bu görevi gerçekleştirmek için ThreadNetworkClient
arayüzünün addCredentials()
yöntemini kullanacaksınız. Google Play Hizmetleri depolama alanına eklenen ilk TBR, bu mobil cihaz için Tercih Edilen Kimlik Bilgilerini belirler.
BAID'ine bir dizi Thread ağ kimlik bilgisi ekleyen uygulama, kimlik bilgilerinin sahibi olur ve bu bilgilere erişmek için tüm izinlere sahip olur. Başka uygulamalar tarafından eklenen kimlik bilgilerine erişmeye çalışırsanız PERMISSION_DENIED hatası alırsınız. Ancak tercih edilen kimlik bilgileri, kullanıcı izni alındığında tüm uygulamalarda her zaman kullanılabilir. İş Parçacığı Yönlendirici ağı güncellendiğinde, Google Play Hizmetleri'nde depolanan kimlik bilgilerini güncel tutmanızı öneririz. Bu bilgiler şu anda kullanılmasa da gelecekte daha iyi yolculuklar sunabiliriz.
İlk TBR daha sonra hariç tutulsa bile Tercih Edilen Kimlik Bilgileri Android cihazda kalır. Ayarlandıktan sonra, Thread kimlik bilgilerini yöneten diğer uygulamalar bir getPreferredCredentials()
çağrısından kimlik bilgilerini alabilir.
Google TBR Senkronizasyonu
Android cihazlar Google TBR'leri ile otomatik olarak senkronize edilir. Android'de kimlik bilgisi yoksa cihazlar bu bilgileri ağınızdaki Google TBR'lerden çıkarır ve bu kimlik bilgileri Tercih Edilen Kimlik Bilgileri olur. TBR'ler ile Android cihaz arasında senkronizasyon yalnızca TBR tek bir kullanıcıyla veya aynı Akıllı Ev'de ( Yapı) bulunan iki kullanıcıyla eşlenmişse gerçekleşir.
Bu işlem, aynı yapıda olan başka bir Google kullanıcısı Android için GHA veya iOS için GHA'yı kullandığında da gerçekleşir. iOS için GHA söz konusu olduğunda, tercih edilen kimlik bilgisi yoksa tercih edilen kimlik bilgileri iOS depolama alanında ayarlanır.
Aynı ağda farklı tercih edilen kimlik bilgileri içeren iki Android cihaz (veya Android + iGHA) varsa TBR'yi başlangıçta yapılandıran cihaz TBR'de öncelikli olur.
3. taraf TBR ilk katılım
Kimlik bilgisinin depolama alanı şu anda kullanıcının Akıllı Ev cihazı ( Yapı) kapsamında değil. Her Android cihazın BAID depolama alanı olur. Ancak, ağda bir Google TBR olduğunda, iOS için Google Home uygulamasını çalıştıran diğer Android cihazlar ve iOS cihazlar bu TBR ile senkronize edilir ve telefon depolama alanında yerel kimlik bilgileri belirlemeye çalışır.
Yeni bir OOB TBR bir ağ oluşturmadan önce Android'in depolama alanında tercih edilen bir ağın mevcut olup olmadığını kontrol etmek önemlidir.
- Tercih edilen bir ağ varsa satıcı bunu kullanmalıdır. Bu, mümkün olduğunda Thread cihazlarının tek bir Thread ağına bağlanmasını sağlar.
- Tercih edilen ağ bulunmadığında yeni bir kimlik bilgisi grubu oluşturun ve bunu Google Play Hizmetleri'nde TBR'nize atayın. Android, bu kimlik bilgilerini Google tabanlı tüm TBR'lerde belirlenen standart kimlik bilgileri olarak kabul eder. Diğer tedarikçiler ise daha fazla cihazla ağ erişiminizi ve dayanıklılığınızı artırabilir.
4. Android Uygulamanızı Klonlama ve Değiştirme
Thread API'ye yapılacak olası ana çağrıları gösteren bir Android uygulaması oluşturduk. Bu kalıpları uygulamanızda kullanabilirsiniz. Bu codelab'de, GitHub'dan Matter için Google Home Örnek Uygulaması'nı klonlayacağız.
Burada gösterilen tüm kaynak kodları, örnek uygulamada zaten kodlanmıştır. Uygulamayı kendi ihtiyaçlarınıza göre değiştirmeye davet edildiniz ancak işlevselliği incelemek için uygulamayı klonlayabilir veya önceden oluşturulmuş ikili programları çalıştırabilirsiniz.
- Şunu kullanarak klonlayın:
$ git clone https://github.com/google-home/sample-apps-for-matter-android.git
- Android Studio'yu indirip açın.
- Dosya > Klonlanan deponuzu açın ve işaret edin.
- Android telefonunuzda geliştirici modunu etkinleştirin.
- Bir USB kablosuyla bilgisayarınıza bağlayın.
- Uygulamayı Android Studio'da <Cmd+R> tuşlarına basarak çalıştırın (OS X) veya <Ctrl+R> (Win, Linux)
- Direksiyona gidin -> Geliştirici Yardımcı Programları -> Thread Ağı
- Mevcut farklı seçeneklerle etkileşime geçin. Aşağıdaki bölümlerde, her düğmede yürütülen kodu açacağız.
Tercih edilen kimlik bilgileri mevcut mu?
Bir TBR üreticisinin Google'a sorması gereken ilk soru, cihazda tercih edilen bir kimlik bilgisi grubunun mevcut olup olmadığıdır. Bu, akışınızın başlangıç noktası olmalıdır. Aşağıdaki kod, kimlik bilgilerinin varlığıyla ilgili GPS'i sorgular. Kimlik bilgisi paylaşılmadığından kullanıcı izni istemiyor.
/** * Prompts whether credentials exist in storage or not. Consent from user is not necessary */ fun doGPSPreferredCredsExist(activity: FragmentActivity) { try { // Uses the ThreadNetwork interface for the preferred credentials, adding // a listener that will receive an intentSenderResult. If that is NULL, // preferred credentials don't exist. If that isn't NULL, they exist. // In this case we'll not use it. ThreadNetwork.getClient(activity).preferredCredentials.addOnSuccessListener { intentSenderResult -> intentSenderResult.intentSender?.let { intentSender -> ToastTimber.d("threadClient: preferred credentials exist", activity) // don't post the intent on `threadClientIntentSender` as we do when // we really want to know which are the credentials. That will prompt a // user consent. In this case we just want to know whether they exist } ?: ToastTimber.d( "threadClient: no preferred credentials found, or no thread module found", activity ) }.addOnFailureListener { e: Exception -> Timber.d("ERROR: [${e}]") } } catch (e: Exception) { ToastTimber.e("Error $e", activity) } }
GPS tercih edilen kimlik bilgilerini alma
Böyle bir durum söz konusuysa kimlik bilgilerini okumak istersiniz. Önceki kodla tek fark, intentSenderResult
öğesini aldıktan sonra, gönderenden gelen bu sonucu kullanarak bir amaç oluşturmak ve başlatmak istemenizdir.
Kodumuzda, orijinal kod ViewModel'de (ThreadViewModel.kt) ve intent gözlemcileri Etkinlik Bölümü'nde ( ThreadFragment.kt) olduğundan kuruluş/mimari amacıyla bir MutableLiveData<IntentSender?>
kullanırız. Dolayısıyla, intentSenderResult canlı verilere yayınlandığında, bu gözlemcinin içeriğini yürüteceğiz:
viewModel.threadClientIntentSender.observe(viewLifecycleOwner) { sender -> Timber.d( "threadClient: intent observe is called with [${intentSenderToString(sender)}]" ) if (sender != null) { Timber.d("threadClient: Launch GPS activity to get ThreadClient") threadClientLauncher.launch(IntentSenderRequest.Builder(sender).build()) viewModel.consumeThreadClientIntentSender() } }
Bu işlem, kimlik bilgilerinin paylaşılmasıyla kullanıcı iznini tetikler ve onaylanırsa şunun üzerinden içerik döndürür:
threadClientLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> if (result.resultCode == RESULT_OK) { val threadNetworkCredentials = ThreadNetworkCredentials.fromIntentSenderResultData(result.data!!) viewModel.threadPreferredCredentialsOperationalDataset.postValue( threadNetworkCredentials ) } else { val error = "User denied request." Timber.d(error) updateThreadInfo(null, "") } }
Kimlik bilgilerinin MutableLiveData<ThreadNetworkCredentials?>
ile nasıl paylaşılacağı aşağıda açıklanmaktadır.
GPS kimlik bilgilerini ayarlama
Mevcut olup olmamasına bakılmaksızın TBR'nizi Google Play Hizmetleri'ne kaydetmeniz gerekir. Uygulamanız, TBR'nizin Sınır Aracısı Kimliği ile ilişkili kimlik bilgilerini okuyabilen tek uygulama olur. Ancak TBR'niz kaydeden ilk kullanıcı olursa bu kimlik bilgileri, Tercih Edilen Kimlik Bilgileri kümesine kopyalanır. Kullanıcı yetki verdiği sürece bu bilgilere telefondaki herhangi bir Uygulama tarafından erişilebilir.
/** * Last step in setting the GPS thread credentials of a TBR */ private fun associateGPSThreadCredentialsToThreadBorderRouterAgent( credentials: ThreadNetworkCredentials?, activity: FragmentActivity, threadBorderAgent: ThreadBorderAgent, ) { credentials?.let { ThreadNetwork.getClient(activity).addCredentials(threadBorderAgent, credentials) .addOnSuccessListener { ToastTimber.d("threadClient: Credentials added", activity) }.addOnFailureListener { e: Exception -> ToastTimber.e("threadClient: Error adding the new credentials: $e", activity) } } }
TBR Ürününüz için kimlik bilgilerini ayarlama
Bu bölüm her tedarikçi firmanın özelindedir. Bu codelab'de ise DBUS+Python HTTP Rest Server veya OTBR'deki yerel HTTP Dinlenme Sunucusu aracılığıyla uyguluyoruz.
/** * Creates credentials in the format used by the OTBR HTTP server. See its documentation in * https://github.com/openthread/ot-br-posix/blob/main/src/rest/openapi.yaml#L215 */ fun createJsonCredentialsObject(newCredentials: ThreadNetworkCredentials): JSONObject { val jsonTimestamp = JSONObject() jsonTimestamp.put("Seconds", System.currentTimeMillis() / 1000) jsonTimestamp.put("Ticks", 0) jsonTimestamp.put("Authoritative", false) val jsonQuery = JSONObject() jsonQuery.put( "ActiveDataset", BaseEncoding.base16().encode(newCredentials.activeOperationalDataset) ) jsonQuery.put("PendingTimestamp", jsonTimestamp) // delay of committing the pending set into active set: 10000ms jsonQuery.put("Delay", 10000) Timber.d(jsonQuery.toString()) return jsonQuery } //(...) var response = OtbrHttpClient.createJsonHttpRequest( URL("http://$ipAddress:$otbrPort$otbrDatasetPendingEndpoint"), activity, OtbrHttpClient.Verbs.PUT, jsonQuery.toString() )
TBR Ürününüzden kimlik bilgilerini alma
Daha önce gösterildiği gibi, TBR'nizden kimlik bilgilerini almak için GET HTTP fiilini kullanın. Örnek Python komut dosyasını inceleyin.
Derleme ve İçe Aktarma
Android uygulamanızı oluştururken, Google Play Hizmetleri İş Parçacığı Modülü'nü desteklemek için manifest, derleme ve içe aktarma işlemlerinizde değişiklik yapmanız gerekir. Aşağıdaki üç snippet'te yapılan eklemelerin çoğu özetlenmektedir.
Örnek uygulamamızın temel olarak Matter devreye alma işlemi için tasarlandığını unutmayın. Bu nedenle, Manifest ve Gradle dosyaları yalnızca Thread kimlik bilgilerini kullanmak için gereken eklemelerden daha karmaşıktır.
Manifest değişiklikleri
<manifest xmlns:android="http://schemas.android.com/apk/res/android" (...) <!-- usesCleartextTraffic needed for OTBR local unencrypted communication --> <!-- Not needed for Thread Module, only used for HTTP --> <uses-feature (...) android:usesCleartextTraffic="true"> <application> (...) <!-- GPS automatically downloads scanner module when app is installed --> <!-- Not needed for Thread Module, only used for scanning QR Codes --> <meta-data android:name="com.google.mlkit.vision.DEPENDENCIES" android:value="barcode_ui"/> </application> </manifest>
Build.gradle
// Thread Network implementation 'com.google.android.gms:play-services-threadnetwork:16.0.0' // Thread QR Code Scanning implementation 'com.google.android.gms:play-services-code-scanner:16.0.0' // Thread QR Code Generation implementation 'com.journeyapps:zxing-android-embedded:4.1.0' // Needed for using BaseEncoding class implementation 'com.google.guava:guava:31.1-jre'
İlgili içe aktarmalar
// Thread Network Module import com.google.android.gms.threadnetwork.ThreadNetworkCredentials import com.google.android.gms.threadnetwork.ThreadBorderAgent import com.google.android.gms.threadnetwork.ThreadNetwork // Conversion of credentials to/fro Base16 (hex) import com.google.common.io.BaseEncoding // HTTP import java.io.BufferedInputStream import java.io.InputStream import java.net.HttpURLConnection import java.net.URL import java.nio.charset.StandardCharsets // Co-routines for HTTP calls import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch // JSON import org.json.JSONObject // Logs import timber.log.Timber // mDNS/SD import android.net.nsd.NsdServiceInfo // QR Code reader / writer import com.google.mlkit.vision.barcode.common.Barcode import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions import com.google.mlkit.vision.codescanner.GmsBarcodeScanning import com.google.zxing.BarcodeFormat import com.google.zxing.MultiFormatWriter import com.journeyapps.barcodescanner.BarcodeEncoder
5. mDNS/SD Keşfi
Örnek uygulamamız, ağdaki kullanılabilir İş Parçacığı Sınırı Yönlendiricileri ve ilgili BAID'lerinin listesini oluşturmak için mDNS/SD keşfini kullanır.
Bu, TBR'nizin bilgilerini GPS kimlik bilgilerinin depolama alanına girerken çok yararlı olur. Ancak kullanımı bu codelab'in kapsamı dışındadır. NSDManager Android Service Discovery kitaplığını kullanıyoruz. Kaynak kodunun tamamına ServiceDiscovery.kt
'teki Örnek Uygulama'dan ulaşabilirsiniz.
6. Konuyu toparlamak gerekirse
Bu görüşmeleri uyguladıktan veya Örnek Uygulamayı kullandıktan sonra RPi OTBR'yi kullanmaya tamamen başlayabilirsiniz. Örnek Uygulamamızda 8 düğme gösteriliyor:
TBR'nize ilk katılım sırası şu şekildedir:
- Tercihli kimlik bilgilerinin mevcut olup olmadığını sorgu (mavi, 1. satır)
- Yanıta bağlı olarak
- GPS tercih edilen kimlik bilgilerini al (mavi, 2. satır)
- GPS'de TBR kimlik bilgilerini ayarla (mavi, 3. satır) -> TBR'nizi seçin -> Rastgele Oluştur -> Ağ adını girin -> Tamam
- Tercih ettiğiniz kimlik bilgilerini belirlediğinize göre Set RPi OTBR credentials (RPi OTBR kimlik bilgilerini ayarla) seçeneğini kullanarak bunları OTBR'nize ayarlayın. Bu işlem, bu kimlik bilgilerini bekleyen gruba uygular.
Örnek uygulama için varsayılan olarak 10 saniye gecikme kullanılır. Bu nedenle, bu sürenin ardından RPi TBR'nizin (ve ağında bulunabilecek diğer düğümlerin) kimlik bilgileri yeni veri kümesine taşınır.
7. Sonuç
Bu codelab'de örnek bir Android Uygulaması klonladık ve Google Play Hizmetleri'ndeki Thread Storage API'leri. Bu API'leri kullanarak, bir tedarikçinin TBR'sini gösteren ve bir RPi TBR'de ilk katılım sürecini yürütmek için kullanabileceğimiz ortak bir veri kümesi oluşturduk.
Bir kullanıcının tüm TBR'lerinin aynı ağda olması, Thread Network'ün direncini ve erişimini artırır. Ayrıca, kimlik bilgilerine erişimleri olmadığından uygulamaların Thread Cihazları'na dahil edemediği hatalı kullanıcı yolculuklarını da önler.
Bu codelab'in ve Örnek Uygulamalar'ın, kendi Uygulamanızı ve İş Parçacığı Yönlendirici ürününüzü tasarlamanıza ve geliştirmenize yardımcı olacağını umuyoruz.
8. Referanslar
RCP ortak işleyeni
DBUS