OneNet使用起來要比lewei50複雜一些,它沒有前臺須要本身開發。命令下發也和以前介紹的lewei50有一些區別,這裏着重介紹一下使用MQTT協議來進行通信。緩存
1、準備服務器
一、Esp8266開發板(+燒寫器或者直接用WeMos D1 Wifi之類的就不要燒寫器了)網絡
二、Arduino IDE for VS函數
三、OneNet註冊工具
2、OneNet配置測試
OneNet總體結構上與lewei50不一樣,它從產品開始下面能夠有若干按APIKEY組織的設備羣組(實名認證與否決定了能用多少產品和設備),每一個設備下面能夠有若干傳感器和控制器(測試過程未發現個數限制)。而其中控制器狀態是和傳感器一塊兒上傳的,服務器下發的命令以Qos0進行,即不接收回復。更多的內容就請參考開發文檔吧。ui
一、進入開發者中心建立產品編碼
接入方式選擇公開協議,設備接入協議選擇MQTT。建立完成後,會獲得一個APIKEY,這個APIKEY能夠用於訪問產品下的任何一個設備。固然,也能夠建立一個新的APIKEY,而後設置該APIKEY關聯的設備。spa
二、建立設備3d
其中設備名稱和鑑權信息都是自定義,鑑權信息與設備ID是通用的,若是想要用MAC進行綁定那這裏鑑權信息就填寫設備的MAC地址,我就隨便填了一個。固然這是與前臺相關的內容,不在此討論。
三、建立數據流模板
數據流名稱最好簡明,由於須要ESP8266處理的字符不少,而其資源也不是十分充裕。須要主意的是,每個數據流就是一個傳感器或控制器。即控制器也在這裏建立。建立完成以後就能夠把數據流和產品關聯起來,爲了直觀觀察,咱們再在「應用管理」裏面建立一個簡單的應用:
選擇這個開關控件,而後在右面除了關聯設備數據流以外,設置一下開關開值和開關關值:
其默認值開爲1,關爲0。這裏說明一下該參數在服務器下發命令時如何被解釋(以圖中的01和00爲例):
把每一個數字解釋爲1字節進行下發,因此上面00被接收到的是{0,0}這樣的,它與0徹底不一樣。而右面的按鈕我設置的開關之分別爲十一、10,因此在後面的代碼中前一字節被做爲分組標誌,後一字節被做爲開關值。
3、編碼
一、IDE和配置
與前一篇同樣,這裏使用Arduino IDE(實際上我用的是for vs,操做差很少,有代碼提示而已)來進行編寫。開發板選擇NodeMCU1.0(ESP-12E Module),而不論使用的是WeMos D1 Wifi仍是其餘8針、IO全引出啥的(估計魔改串口4針的是玩不了的)。其餘配置以下:
二、層次邏輯
a、Esp8266wifi.h負責鏈接WIFI
b、pubsubclient.h負責MQTT通信(可變頭和載體須要自定義,該庫只負責Fixed header)
c、ArduinoJson.h負責構建載體中數據部分,具體格式請參考OneNet MQTT開發文檔
d、eeprom.h負責將配置寫到esp8266模塊中和讀取,這個的寫操做與arduino開發板是不一樣的
三、主要代碼示例
這裏主要說一下MQTT部分,其餘部分再也不贅述。
a、pubsubclient總述:
WiFiClient wClient;
PubSubClient mClient(mServerAddress,mServerPort, mCallback,wClient);
其中,mCallback是一個回調函數,該函數用於處理服務器發來的消息,其簽名以下:
void mCallback(char* topic, byte* payload, unsigned int length)
其中topic是話題,包含了topicName,Payload是實際下發的內容,例如上面的水泵開關開則有2字節:0 1。length指payload字節數。要處理的服務器數據就在該函數處理就能夠了,可是最好別太長,不然影響數據的響應速度。
b、鏈接MQTT服務器
bool ConnectServer() { int waitConst = 0; if (!mClient.connected()) { //id="設備id",user="產品id",pass="APIkey" mClient.connect(DeviceID, ProductID, APIKey); while (!mClient.connected() && waitConst<20) { delay(100); waitConst++; } Serial.println((String)"ConnectServer " + mClient.connected()); } return mClient.connected();// mClient.state() == MQTT_CONNECTED; }
在Onenet開發者頁面的說明後面有一段問答,其中明確說明了上面的參數如何傳遞,上面註釋寫的很是清楚了;固然也能夠用前面提到的設備鑑權信息代替APIKEY字段做爲password傳入。
c、發佈話題
bool PubTopic(String TopicName,String Json) { memset(msg_buf, 0, MQTT_MAX_PACKET_SIZE); //清理MQTT消息緩存 //設置可變頭 msg_buf[0] = char(0x03); //包數據格式標誌 msg_buf[1] = char(Json.length() >> 8); //高位在後 msg_buf[2] = char(Json.length() & 0xff); //低位在前 //設置數據 memcpy(msg_buf + 3, Json.c_str(), Json.length()); mClient.publish(TopicName.c_str(), (uint8_t*)msg_buf, Json.length() + 3); //設置發送長度以避免中間的00使得自動斷定長度出錯。 }
可變頭部分指明瞭使用哪一種數據包格式,設置了Json數據長度。這一部分有若干種數據格式,具體參考開發文檔,上面代碼中使用的type3格式在說明文檔中的說明以下:
數據類型3(type == 3)格式說明:
Byte 1 |
數據點類型指示:type=3 // JSON格式2字符串 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
1 |
Byte 2 |
//指示後面字符串長度 固定兩字節長度高位字節,值爲0x00 |
|
|
|
|
|
|
|
|
Byte 3 |
固定兩字節長度低位字節,值爲0x46 |
|
|
|
|
|
|
|
|
Byte 4 |
通用格式: { 「datastream_id1」:」value1」, 「datastream_id2」:」value2」, … }
示例: {「temperature」:22.5,」humidity」:」95.2%」} |
|
|
|
|
|
|
|
|
… … … … |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
||
Byte n |
|
|
|
|
|
|
|
|
看的時候無視這沒頭沒尾的0x00、0x46吧。參考代碼上面的代碼就能夠了。其中Json的構建在上一篇中已經說得很是清楚、十分深刻了,完成這個代碼構建是基礎中的基礎了,這裏再也不說明。
4、ESP8266的EEPROM
關於這個問題是看樂鑫的開發文檔仍是怎麼的才能解決提及來沒意義,上你們最喜歡的積木:
void SaveConfig(int cfgidx, String val) { //esp8266的EEPROM與Areduino的使用不一樣 //一、申請操做緩存 EEPROM.begin(eBlockSize); //二、寫入數據 for (int i = 0; i < eBlockSize; i++) { EEPROM.write(cfgidx*eBlockSize + i, val[i]); } //三、保存數據更改 EEPROM.commit(); }
好了,這篇就介紹到這裏,也不把OneNet上面建立的這個設備的應用嵌入到這裏了,願意作的本身作一下就能夠看到效果了。我這如今就幾塊開發板,USB已經插了一堆堆各類東西,不可能長期保持這東西在線的。
5、網絡調試工具
這個不像以前的一些WIFI應用調試起來那麼簡單,有時候代碼看着貌似都沒問題就是不過,而服務器端沒有提供底層的數據調試功能,通常的SOCKET調試工具也不提供MQTT服務器,本身架設一個也須要大篇幅的工做。因此具體WIFI發送了什麼仍是要一些其餘工具。首先,得讓數據從電腦上過去咱們纔有機會在電腦上下個鉤子把數據呈現出來,因而我安了一個隨身WIFI,設置好以後,讓ESP8266鏈接它,至於用什麼WIFI軟件無所謂,根本別期望他們提供底層數據,也沒期望去勾它們,那太麻煩了。開發一個新的東西也得不償失,仍是用專業工具吧,祭出神器winpcap就解決一切了。使用winpcap的網絡封包工具不少,其中作的好的也很多,Ethereal就是其中一個,如今可能叫Wireshark。