)
前陣子在幫某物聯(lián)網項目調試Mesh組網遇到一個特別典型的卡點配網器掃描設備時始終看不到那臺待配網的燈控設備。日志顯示掃描正常信道正常濾波條件也加了可就是捕捉不到那個關鍵的廣播包。折騰了大半天最后發(fā)現(xiàn)是設備端的Unprovisioned Device Beacon廣播沒被正確初始化——簡單說這臺設備壓根就沒有向外面“喊”它需要入網。這個場景在藍牙Mesh開發(fā)里太常見了。很多人一上來就研究配網流程的加密、公鑰交換、認證邏輯卻忽略了最前端那個不起眼的beacon。實際上整個配網能否成功第一步就取決于這個廣播包能不能被配網器穩(wěn)定地發(fā)現(xiàn)。這篇內容我就把Unprovisioned Device Beacon這件事從頭到尾拆清楚包括它在配網鏈路里的定位、數(shù)據(jù)包結構、配網時各階段的狀態(tài)流轉以及我在不同項目里踩過的坑和排查方法。不管是剛接觸藍牙Mesh的初學者還是已經被配網問題折磨過的老手這部分內容應該都能幫上忙。1. 未入網設備憑什么被“看見”Unprovision Beacon的定位1.1 它是配網流程的第一個突破口藍牙Mesh網絡和傳統(tǒng)BLE最直觀的區(qū)別在于Mesh里的設備不是天生就能互相通信的。一個新出廠的設備比如一個燈泡、一個傳感器它內部其實已經跑著完整的Mesh協(xié)議棧但并不知道自己是這個網絡里的誰也不知道網絡密鑰是什么。在它被配置之前它就是一個“游離者”——能看到周圍的環(huán)境卻不被任何現(xiàn)有網絡接納。這里就出現(xiàn)了一個問題Mesh網絡的配網器Provisioner怎么知道周圍有這么一個待入網的設備尤其是當設備沒有任何屏幕、沒有按鍵、甚至沒有指示燈的時候配網器總得有個方式發(fā)現(xiàn)它。Unprovisioned Device Beacon未配網設備信標就是這個機制的最前端。它本質上是一個BLE廣播包周期性地向外發(fā)送包里唯一的目的就是告訴所有在監(jiān)聽的配網器“我在這里我是誰我準備好被配置了?!蔽覀兂Uf的“beacon”可能指的是蘋果的iBeacon也可能指各種室內定位用的信標但Unprovisioned Device Beacon是完全不同的東西。它不承載定位信息不面向普通手機應用提供數(shù)據(jù)而是面向Mesh網絡的配網器承擔的是設備發(fā)現(xiàn)功能。沒有這個廣播包配網器就會對著空氣掃描后面所有流程都無從談起。1.2 兩套beacon別搞混發(fā)現(xiàn)用beacon配網事務則是另一套很多初學者會在這里踩一個概念上的混淆Mesh里其實有兩類和“未配網”密切相關的廣播。一類是Unprovisioned Device Beacon用于讓設備被發(fā)現(xiàn)另一類是配網過程中真正傳輸配網指令的廣播包走的是PB-ADVProvisioning Bearer Advertising基于廣播承載的配網事務機制。兩者的時間先后和職責完全不同。實際運行中是這樣設備先以Unprovisioned Device Beacon的身份對外廣播配網器掃描到它之后由配網器主動發(fā)起配網連接雙方進入配網事務階段。進入事務階段后配網雙方交換的是配網協(xié)議數(shù)據(jù)包Provisioning Protocol PDUs這些數(shù)據(jù)包通過PB-ADV廣播承載但它們的廣播類型已經不再是Unprovisioned Device Beacon而是帶有特定配網事務標識的ADV包。我在調試時就見過一個項目開發(fā)同學一直盯著檢查Unprovisioned Device Beacon的廣播是否正確發(fā)送卻忘了配網事務是靠另一組廣播完成的導致這兩段的鏈路經常被截斷。理解了這個先后關系后面排查問題時就不會在一個地方死磕。1.3 什么時候廣播什么時候停beacon的聲明周期Unprovisioned Device Beacon并不是設備一上電就永遠廣播個不停。它的生命周期取決于設備的存儲狀態(tài)。設備啟動后協(xié)議棧會先檢查非易失性存儲里有沒有保存有效的配網信息NetKey、AppKey、IV Index等。如果沒有——也就是這臺設備從未被配置過或配置信息被主動清除過——協(xié)議棧才會啟動beacon廣播。一旦配網成功設備會寫入配網數(shù)據(jù)此時beacon必須立即停止。這一點在很多項目里看起來理所當然但實際測試中經常翻車后面我會專門講我遇到的一個案例配網成功后beacon沒有停導致設備被重復配網。2. 拆包看本質Unprovisioned Device Beacon數(shù)據(jù)包結構2.1 廣播類型0x29和AD Structure的組裝規(guī)則藍牙Mesh規(guī)范里規(guī)定Unprovisioned Device Beacon的廣播類型值為0x29。整個廣播包遵循BLE標準的AD Structure格式也就是Length、Type、Data三段式。我用一個實際抓包得到的數(shù)據(jù)來拆解AD Structure 1: Length : 0x15 (21字節(jié)) Type : 0x01 (Flags) Data : 0x06 (LE General Discoverable Mode) AD Structure 2: Length : 0x14 (20字節(jié)) Type : 0x29 (Unprovisioned Device Beacon) Data : 16字節(jié)Device UUID 2字節(jié)OOB Information第一個AD Structure是常見的廣播標志告知接收方這是一個通用可發(fā)現(xiàn)的廣播設備。第二個AD Structure才是核心。當配網器掃描時就是靠過濾Type字段是否等于0x29來識別潛在的可配網設備。這里有個細節(jié)值得注意一次廣播包里面只能有一個Type為0x29的AD Structure。如果想把Unprovisioned Device Beacon和其他數(shù)據(jù)比如廠商自定義數(shù)據(jù)、服務UUID拼在一起必須放在不同的AD Structure里。配網器解析時也是獨立解析每個AD Structure的不是要求整個廣播包全是beacon內容。2.2 Device UUID設備唯一的身份證明Device UUID是整個beacon包里最重要的16字節(jié)。它不是什么隨機數(shù)而是設備的靜態(tài)標識符在設備生產階段就寫入非易失性存儲配網后也不會改變。配網器通過它識別設備Mesh網絡后續(xù)對設備的操作也基于這個UUID建立對應關系。生產環(huán)節(jié)對UUID的管理是個容易被忽視的工作。有些工廠在燒錄時用的是同一個UUID模板導致一批設備全部撞車。那場面很經典配網器掃描到一個UUID卻對應了好幾臺物理設備完全無法區(qū)分。更隱蔽的問題是UUID一旦在生產后需要修改牽扯到整臺設備的重新燒錄和配網數(shù)據(jù)清除非常麻煩。正確的是在產線階段就保證UUID唯一并且和產品序列號、MAC地址等建立映射關系寫進設備信息表。調試時我習慣先用串口或板載調試工具讀取設備的真實UUID再手動添加進配網器的過濾條件里而不是通過掃描列表去碰運氣。2.3 OOB Information字段怎么用Device UUID后面跟著2字節(jié)的OOB Information。這個字段描述的是設備在配網認證階段支持哪些帶外信息的輸入輸出方式。常見值包括OOB值含義典型場景0x0000不支持任何OOB僅支持None認證0x0001支持其他OOB廠商自定義帶外通道0x0002支持URIbeacon中附帶URI Hash0x0004支持數(shù)值輸入按鍵輸入6位數(shù)字0x0008支持數(shù)值輸出顯示屏顯示6位數(shù)字0x0020支持字母數(shù)字輸入鍵盤輸入字母數(shù)字配網器發(fā)現(xiàn)beacon后會根據(jù)OOB值判斷這臺設備能采用哪種認證方式。實際項目里如果配網器端配置了固定要求數(shù)字輸入而設備端OOB字段聲明不支持任何OOB配網必然失敗。這個字段的聲明和配網器的要求必須對得上否則就是白調試半天。我踩過的一個典型案例是設備明明帶了一塊小屏幕可以顯示動態(tài)數(shù)字用于認證但SDK里的OOB信息配置被某次固件更新意外改成了0x0000。配網器認為設備沒有任何OOB能力只能走最簡單的無認證流程這在安全性要求高的場景下直接導致配網被服務端策略拒絕。2.4 可選的URI Hash字段有部分設備還會在beacon后面追加一個URI Hash字段用來進一步標識設備類型或產品信息。URI Hash簡單說就是把一個URI比如https://example.com/light/001經過哈希算法后得到的固定長度值。配網器可以先通過URI Hash識別出設備的類型再決定是否發(fā)起配網減少掃描到不相關設備時的干擾。如果不需要設備類型分類這個字段可以省略。包長度更短廣播成功率也會更高尤其是當廣播信道比較擁堵時。3. 配網鏈路全解析從被掃描到完成配置的五個階段3.1 建立邀請邀請是雙向的當配網器通過Unprovisioned Device Beacon發(fā)現(xiàn)設備后會主動向設備發(fā)送一個Provisioning Invite包。這一步很多人理解成“配網器向設備打招呼”實際上它是配網事務的正式啟動信號。設備收到Invite包后會回復一個Invite Acknowledgement同時雙方基于這個交互確定后續(xù)的數(shù)據(jù)包格式、重傳策略和協(xié)議版本。如果設備端沒有正確維護beacon狀態(tài)或者已經進入半配網狀態(tài)比如上次配網超時沒有清理干凈這一階段就會多次超時。值得注意的是配網器此處不再監(jiān)聽0x29類型的廣播而是直接和該設備建立點對點的配網承載。我在實際調試驗證時發(fā)現(xiàn)不少SDK在進入這一步后設備端的beacon廣播仍然在繼續(xù)這在協(xié)議層面是允許的但會增加不必要的空口占用建議在業(yè)務層面主動處理。3.2 公鑰交換與認證安全的關鍵環(huán)節(jié)邀請階段完成后配網雙方進入Public Key交換階段。雙方各自的公鑰如果通過beacon的OOB字段預先聲明支持帶外交換也可以先通過帶外方式交換提高安全性。這一步完成后配網器會發(fā)起Authentication階段。認證階段基于之前OOB字段聲明的能力來執(zhí)行。如果聲明的是輸出顯示設備端生成一個六位數(shù)字并顯示在屏幕或標簽上用戶把這個數(shù)字輸入到配網器完成認證如果聲明的是輸入按鈕則是配網器端生成數(shù)字用戶在設備上按鍵輸入。整個過程是為了防止中間人攻擊。我在這個階段最常碰到的問題是設備端和配網器端的OOB類型配置不一致。很多開發(fā)者以為只要配網器端支持某種方式就行忘了設備端的beacon OOB字段也要同步聲明。排查時先看抓包里beacon的OOB值再對照配網器端的認證策略往往一眼就能定位。3.3 下發(fā)配網數(shù)據(jù)分配網絡地址與密鑰認證通過后配網器給設備分配關鍵參數(shù)單播地址、NetKey、AppKey、IV Index等然后通過加密通道發(fā)送給設備。這個階段也是整個配網過程最復雜的一步包含多條配網協(xié)議PDU的往返交互。設備收到這些數(shù)據(jù)后會寫入自己的非易失性存儲然后向配網器發(fā)送Provisioning Complete消息。配網器收到這條消息后才會認為配網流程真正完成。此時設備端的協(xié)議棧會把自身狀態(tài)切換為已配網節(jié)點停止Unprovisioned Device Beacon廣播。這里我建議每一條關鍵PDU的成功與否都要看兩端日志里的狀態(tài)機轉換點。光看一條“配網成功”的日志往往不夠因為有些SDK會在設備本地狀態(tài)已更新但配網器尚未確認時提前報成功導致網絡里出現(xiàn)一個半配網狀態(tài)的尷尬節(jié)點。3.4 配網完成后的beacon狀態(tài)切換配網完成后設備從Unprovisioned Device狀態(tài)變成Provisioned Node狀態(tài)。此時Unprovisioned Device Beacon必須停止如果設備支持PB-GATT可能還會切換到可連接廣播狀態(tài)允許手機App通過GATT連接對它做后續(xù)配置。這一塊是很多產品真正上了產線、或者到了用戶手里之后出問題的地方。有些設備明明已經配好網在售后排查時會發(fā)現(xiàn)又被重新配了一次原因就在于設備重啟時存儲讀取失敗協(xié)議棧誤判設備仍未配網重新打開了beacon廣播。配合抓包工具能夠清楚地看到配網成功的瞬間0x29類型的廣播停止發(fā)送。如果這個廣播沒?;究梢詳喽ㄊ谴鎯懭牖蛘郀顟B(tài)標志沒有正確完成這就是一個清晰的排查方向。4. 現(xiàn)場翻車實錄三個典型問題及定位思路4.1 掃描不到beacon先分清“沒廣播”還是“沒掃到”這個問題我開場就提到了也是大家問得最多的。它的排查點可以按下面這張表一層層排除檢查項怎么查常見根因廣播開關看SDK日志確認beacon enable接口被調用其他功能誤關了廣播設備狀態(tài)讀存儲標志位確認設備處于未配網狀態(tài)存儲區(qū)殘留配網信息廣播周期抓包確認廣播間隔是否符合設定值周期過長導致等待窗口不夠信道干擾觀察2.4GHz頻段占用情況Wi-Fi、藍牙設備密集配網器濾波檢查掃描參數(shù)中UUID過濾是否正確UUID配置成另一臺設備排查順序從設備端到配網器端從簡單到復雜。先確認廣播有沒有發(fā)出來再確認配網器能不能掃到然后再去查信道和干擾。不要一上來就懷疑空口環(huán)境有問題設備端SDK初始化順序導致beacon沒啟動這種情況我見到的概率遠大于信道問題。一種高效的定位方式是在設備旁邊放一個支持廣播過濾的抓包工具先看設備上電后有沒有發(fā)出任何廣播。如果沒有任何廣播報告那就是設備端的問題如果有再對照配網器端的掃描報告看是不是被濾掉了。這一步能把問題范圍縮小一大半。4.2 多設備同時配網碰撞和重試的權衡項目現(xiàn)場經常是一整箱設備同時上電然后配網器一個個掃描配網。這種情況下大量設備同時廣播Unprovisioned Device Beacon三個廣播信道很容易發(fā)生碰撞導致部分設備遲遲不被發(fā)現(xiàn)。藍牙Mesh協(xié)議對廣播間隔有隨機退避機制設備每次廣播的時間間隔會根據(jù)一個隨機數(shù)在設定值附近浮動避免多設備完全同步廣播。但實際項目里如果不設置隨機退避或間隔浮動過窄碰撞概率會顯著上升。我的做法是把默認廣播間隔設置到200ms~500ms范圍內浮動并根據(jù)設備數(shù)量做動態(tài)調節(jié)。比如第一次上電的120秒內廣播間隔可以短一點讓配網器盡快發(fā)現(xiàn)之后如果沒有被配網逐步拉長間隔降低功耗。這個策略在實際項目里既保證了配網速度又照顧了長期待機場景。4.3 配網成功后設備還在廣播重復入網隱患剛才提到的重復入網問題實際調試中繞不開。有一次我排查一個節(jié)點的異常行為它已經成功入網也能收發(fā)Mesh消息但每次配網器重新掃描時還會發(fā)現(xiàn)它。抓包一看Unprovisioned Device Beacon還在周期性地發(fā)。原因出在設備SDK的通知順序上配網完成后協(xié)議棧先發(fā)了Provisioning Complete事件給應用層應用層更新了自身的業(yè)務狀態(tài)但設備存儲中的配網標志位是在另一條邏輯里更新的而這條邏輯因為某個分支條件沒滿足被跳過了。設備重啟后存儲讀不到配網標志于是又把自己當成未配網設備。這一類問題排查起來很耗時間因為表面看起來配網功能是正常的。建議在你的代碼里做一個簡單的斷言配網完成事件之后立刻讀一次存儲標志位確認已經寫成功。這個斷言放在量產固件里也是一種保護防止用戶在配網后因設備重啟出現(xiàn)“已配網變未配網”的詭異現(xiàn)象。5. 抓包分析的關鍵姿勢把beacon從空中釘在紙上5.1 抓包前的準備工作和過濾條件設置調試藍牙Mesh抓包能力是必須的。不要靠“我覺得應該沒問題”來排查直接把空中報文拿下來看很多問題當場就清楚了。抓Unprovisioned Device Beacon準備工作其實就那么幾項抓包工具支持至少3個廣播信道的同時監(jiān)聽天線靠近設備周圍少一些其他2.4GHz設備。抓包開始后先不做過濾地監(jiān)聽一段時間確認能看到設備發(fā)出的其他廣播再添加過濾條件。過濾時我是直接過濾廣播類型0x29或者過濾beacon的AD Type字段。具體到抓包軟件里通常是通過自定義AD Type過濾表達式實現(xiàn)的不同抓包工具寫法略有不同但原理都是匹配ad_type0x29。這里特別提醒很多抓包工具默認只顯示設置了“可連接廣播”標志的數(shù)據(jù)包而Unprovisioned Device Beacon不一定包含Connectable標志容易被隱藏掉。如果發(fā)現(xiàn)抓不到先檢查工具的顯示過濾條件把所有廣播類型顯示出來再看。5.2 如何從抓包結果判斷廣播是否健康抓包結果里最值得關注的三個指標是廣播間隔的穩(wěn)定性、RSSI的波動范圍以及包內數(shù)據(jù)的一致性。廣播間隔方面如果設定值是200ms實際抓包發(fā)現(xiàn)間隔忽長忽短、甚至出現(xiàn)幾百毫秒的空檔說明設備端的廣播調度有問題可能被其他高優(yōu)先級任務搶占。RSSI波動大說明設備天線和抓包器之間的距離或方位在變化或者反射干擾嚴重這時候就要調整物理位置再測。數(shù)據(jù)一致性方面我遇到過設備廣播里的Device UUID和它實際調試口讀出來的UUID對不上后來發(fā)現(xiàn)是同一條SDK代碼路徑下有兩份UUID配置初始化時用了舊的緩存。這種問題不抓包根本發(fā)現(xiàn)不了通過對比beacon里的UUID和固件配置的UUID就能迅速定位。5.3 結合協(xié)議棧日志做交叉驗證抓包只解決了一部分問題另一部分要靠設備端協(xié)議棧日志。拿配網失敗的情況舉例beacon在空中反復發(fā)出配網器也掃到了但配網流程中途斷開。這時候抓包能告訴你的只是“連接建立失敗”或“某條消息超時”但具體是哪一層的狀態(tài)機出了問題通常要看設備端日志里的狀態(tài)轉換記錄。聯(lián)合分析時我習慣把抓包時間戳和SDK日志時間戳對齊先看抓包里配網器發(fā)送Invite的時間再在SDK日志里找設備收到Invite的時間。如果兩者相差超過幾百毫秒重點看設備端廣播接收窗口是否被關閉如果設備端收到了但沒回復重點看協(xié)議棧狀態(tài)機是否卡在某個中間狀態(tài)。時間戳對齊這塊很多日志默認打印的是系統(tǒng)啟動后的相對時間需要換算成Unix時間戳或帶上RTC時間不然兩邊對不上。我一般會在調試固件里增加一個啟動標志日志打印當前的秒級時間戳方便和抓包時間對應。6. 經驗沉淀幾句不一定寫進文檔的實話6.1 關于廣播參數(shù)的合作經驗廣播間隔和功耗的關系很多人只看理論值但實際做產品時的權衡更多。默認廣播間隔100ms單次廣播功耗大概0.5秒等效電流的幾分之一看似不夸張但如果一個設備被放在貨架上無人配網一年下來累積的功耗相當可觀。我后來在量產項目里用的是兩段式策略開機或復位后2分鐘內以200ms間隔廣播方便用戶快速配網之后如果一直沒被配網切換到1秒或2秒間隔同時降低廣播發(fā)射功率。這個策略在減弱功耗的同時還要保證配網器靠近設備的時候能發(fā)現(xiàn)。具體的間隔數(shù)值需要根據(jù)產品形態(tài)和電池容量來計算沒有放之四海而皆準的答案。6.2 不同SDK實現(xiàn)里的個性差異不同廠商的藍牙Mesh SDK對Unprovisioned Device Beacon的實現(xiàn)有不少細節(jié)差異。有的SDK要求開發(fā)者在使用配網功能前顯式初始化beacon參數(shù)否則默認不廣播有的SDK則把beacon和可發(fā)現(xiàn)模式綁定關閉可發(fā)現(xiàn)模式就會連beacon一起關閉。這就導致一個問題從一個平臺遷移到另一個平臺時不能只看配網主流程的API還得把beacon初始化、OOB配置、廣播參數(shù)這些邊角功能全部檢查一遍。我最開始做跨平臺移植的時候就吃過這個虧原來在某芯片上跑得好好的工程換到另一家的SDK后死活掃不到設備最后發(fā)現(xiàn)是beacon初始化被另一個功能函數(shù)覆蓋了。6.3 還能怎么玩URI Hash與近場配網研究Unprovisioned Device Beacon不只是為了配網能跑通它還可以承載一些產品化的玩法。比如通過URI Hash配網器可以在掃描階段就識別出這是一臺燈具還是傳感器自動彈出對應的配置頁面省去用戶手動選擇設備類型的步驟。還有一種比較實用的擴展思路是結合RSSI做距離門限。利用beacon廣播的RSSI強弱當配網器靠近某臺設備到一定距離時才會觸發(fā)配網這樣可以防止在設備密集環(huán)境下誤配到隔壁的設備。這種方案對廣播功放射頻鏈路一致性要求高需要做相對復雜的校準但在一些高端產品場景里體驗提升非常明顯?,F(xiàn)在回看Unprovisioned Device Beacon它不過是一個只有二十來字節(jié)的廣播包卻在Mesh網絡的入口處扮演著無可替代的角色。很多Mesh配置問題追根溯源到最后都是回到了這個小小的beacon上。分享這些內容也是希望大家在調Mesh配網時先把這個“最初的招呼”打好再談后面那些復雜的加密和握手會順手很多。