設(shè)備證書是生活物聯(lián)網(wǎng)為設(shè)備頒發(fā)的唯一身份憑證。為了快速從下載的設(shè)備證書文件(CSV格式)中讀取每條設(shè)備證書信息,并燒寫到產(chǎn)線上的設(shè)備中,生活物聯(lián)網(wǎng)平臺提供設(shè)備證書分發(fā)工具來幫助您完成CSV文件讀取及分發(fā)工作。您可以根據(jù)本文檔改造您的產(chǎn)線,提高量產(chǎn)效率。
方案介紹
生活物聯(lián)網(wǎng)平臺提供設(shè)備證書分發(fā)工具的方案原理圖如下。
生活物聯(lián)網(wǎng)的設(shè)備身份分發(fā)工具采用Server-Client架構(gòu),Server與Client交互流程圖如下所示。
- Server:由生活物聯(lián)網(wǎng)平臺提供,您下載后可直接使用。
您可以使用生活物聯(lián)網(wǎng)平臺提供的NodeJS SDK(參見本文檔下方Sever端工具使用章節(jié)),來驗證Server端鏈路是否正常。
- Client:部署在產(chǎn)線燒錄儀器或集成到產(chǎn)品固件中(兩者對比如下表所示),需要您自行開發(fā)。
為了方便您快速集成Client,生活物聯(lián)網(wǎng)平臺提供了C SDK供您參考(參見本文檔下方使用C SDK開發(fā)Client章節(jié))。 您集成C SDK后,再自行集成燒錄設(shè)備證書的方式到Client中。
Client部署方式 適用場景 描述 特點 集成到設(shè)備固件中 產(chǎn)線上沒有用于將設(shè)備證書燒寫到芯片/設(shè)備的儀器。 該方案設(shè)備上電后,Client向Server申請身份信息,Client獲取到設(shè)備證書后將這些信息寫入設(shè)備的NVRAM和Flash。 該方案您需要實現(xiàn)以下內(nèi)容:
- 設(shè)計如何觸發(fā)Client去獲取設(shè)備證書的功能。
- Client獲取設(shè)備證書后,需要實現(xiàn)將信息寫入NVRAM和Flash的操作。
- 產(chǎn)線無需部署專門用于燒寫設(shè)備證書的儀器。
- 設(shè)備需要實現(xiàn)Client的功能,因此會占用設(shè)備的部分存儲空間。
- 可以實現(xiàn)批量進(jìn)行身份信息獲取。
部署在產(chǎn)線燒錄儀器上 產(chǎn)線上存在將設(shè)備證書燒寫到芯片/設(shè)備的儀器,如燒錄器或編程器等。 該方案由燒錄軟件實現(xiàn)Client的功能向Server申請身份信息,取得設(shè)備證書后,通過燒錄器和編程器寫入設(shè)備的NVRAM和Flash。 阿里云物聯(lián)網(wǎng)提供了產(chǎn)線分發(fā)App的通信協(xié)議,該方案您需要修改產(chǎn)線燒寫工具按照該通信協(xié)議從產(chǎn)線分發(fā)App獲取設(shè)備證書。
- 設(shè)備無需實現(xiàn)Client的功能,不會為了獲取身份信息功能消耗存儲空間。
- 您需要對燒錄器/編程器進(jìn)行軟件改造。
- 可以根據(jù)產(chǎn)線上的生產(chǎn)設(shè)備數(shù)量、規(guī)模,配置燒錄器/編程器的數(shù)量。
Server-Client協(xié)議說明
Client與Server采用HTTP接口通訊,Client通過POST方法向Server發(fā)送請求,請求協(xié)議以JSON方式放在body里。
字段 | 類型 | 是否必選 | 描述 |
---|---|---|---|
ProductKey | string | 是 | 產(chǎn)品標(biāo)識(生活物聯(lián)網(wǎng)后臺新建產(chǎn)品時生成) |
DeviceID | string | 否 | 設(shè)備ID,唯一標(biāo)識 |
Action | Integer | 是 | 操作
|
請求與響應(yīng)數(shù)據(jù)示例如下。
- Client向Server申請設(shè)備證書請求數(shù)據(jù)
{ "ProductKey":"a1xxxxNW", "DeviceID":"AAxxxx22", "Action":0 }
- Server向Client分發(fā)設(shè)備證書數(shù)據(jù)
{ "ProductKey":"a1xxxxNW", "ProductSecret":"XmDxxxx9R", "DeviceSecret":"NmMExxxxjE5", "CRC32":"B5488744", //CRC32介紹參見下方文檔 "DeviceName":"ZTMxxxxxkUy", "DeviceID":"AABxxxx22", "Status":"OK" }
- 燒錄成功狀態(tài)更新請求
{ "ProductKey":"a1xxxxW", "DeviceID":"AAxxxx22", "Action":1 }
- 燒錄成功狀態(tài)更新返回數(shù)據(jù)
{ "ProductKey": "a1xxxxNW", "DeviceID": "AAxxxx22", "Status": "OK" }
Server分發(fā)設(shè)備證書給Client的數(shù)據(jù)中使用的校驗算法采用標(biāo)準(zhǔn)CRC32(CRC32計算工具網(wǎng)址),多項式為04C11DB7
,初始值與結(jié)果異或值均為FFFFFFFF
,輸入與輸出均取反。校驗payload為設(shè)備憑證(WiFi類設(shè)備為ProductKey、ProductSecret、DeviceName、DeviceSecret;藍(lán)牙類設(shè)備為ProductKey、ProductSecret、DeviceName、DeviceSecret、ProductID)。校驗結(jié)果為4字節(jié)十六進(jìn)制。
CRC32計算結(jié)果校驗工具使用方法的示例如下。
- Java代碼參考實現(xiàn)
import java.nio.ByteBuffer; import java.util.zip.CRC32; public class example { public static void main(String[] args){ ///this is user supplied string String pk = "a1xxxxH"; String dn = "8jQxxxx0WW6"; String ds = "aW60ImxxxxIj61ZbV"; String ps = "EBcjxxxxWxdF"; if ( args.length >= 4) { pk = args[0]; dn = args[1]; ds = args[2]; ps = args[3]; } String payload = pk + dn + ds + ps; ByteBuffer bbuffer = ByteBuffer.allocate(payload.length()); bbuffer.put(payload.getBytes()); //your crc class CRC32 crc = new CRC32(); crc.update(bbuffer.array()); String enc = Long.toHexString(crc.getValue()).toUpperCase(); System.out.println("payload: " + payload); System.out.println("length: " + Integer.toString(payload.length())); System.out.println("crc32: " + enc); } }
- Python代碼參考實現(xiàn)
import zlib pk = "a2xxxx8HZ" dn = "ouxxxxemo" ds = "GD4JauYxxxxsICazhIzb" ps = "4I3xxxxyF96" def Crc32Hash(input_data): crc32 = 0 crc32 = zlib.crc32(input_data, crc32) return format(crc32 & 0xFFFFFFFF, '08X') payload = pk + dn + ds + ps print "payload: ", payload print "length: ", len(payload) print "crc32: ", Crc32Hash(payload)
- 設(shè)備端參考代碼
#define CHIP_CPU_BE #define dwPolynomial_BE 0xEDB88320UL //CRC32 Polynomial #define dwPolynomial 0x04C11DB7UL //CRC32 Polynomial #if defined(CHIP_CPU_BE) #define dwPolynomial dwPolynomial_BE #else #define dwPolynomial dwPolynomial_LE #endif #define CRC_INIT_VALUE 0xFFFFFFFFUL unsigned int calc_crc32(unsigned char *message) { int i, j; unsigned int byte, crc, mask; i = 0; crc = CRC_INIT_VALUE; while (message[i] != 0) { byte = message[i]; // Get next byte. crc = crc ^ byte; for (j = 7; j >= 0; j--) { // Do eight times. mask = -(crc & 1); crc = (crc >> 1) ^ (dwPolynomial_BE & mask); } i = i + 1; } return ~crc; }
Sever端工具使用
Server端由設(shè)備證書分發(fā)和設(shè)備證書管理兩部分組成。
- 下載設(shè)備證書的工具。
- 啟動設(shè)備證書分發(fā)服務(wù)。
- 管理產(chǎn)品批次,并導(dǎo)入設(shè)備證書。
- 查詢產(chǎn)品信息。
(可選)使用NodeJS SDK驗證Server
在設(shè)備證書分發(fā)工具中提供了NodeJS SDK參考實現(xiàn),您可以使用NodeJS SDK來驗證Server獲取設(shè)備證書的鏈路是否正常。
請您根據(jù)以下步驟開發(fā)并運行示例代碼。
使用C SDK開發(fā)Client
設(shè)備獲取身份信息的功能,可采用以下兩種實現(xiàn)方式。
- 產(chǎn)線上將設(shè)備的某個GPIO作為輸入接口,將其拉高或者拉低,當(dāng)設(shè)備上電運行時發(fā)現(xiàn)該GPIO為高或低時,自動連接某個固定的WiFi AP,然后從Server(Server的IP地址需要固定)去申請設(shè)備證書。
- 設(shè)備上電后檢查是否有設(shè)備身份,如沒有設(shè)備身份信息,則自動連接到一個固定的產(chǎn)線AP(AP的SSID和密碼由您自行定義)。此時請參照設(shè)備證書分發(fā)工具提供的C-SDK(調(diào)用
get_triple
)去申請設(shè)備身份。
請您根據(jù)以下步驟基于示例代碼開發(fā)Client。