網頁最後修改時間:2018/08/11
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
若接下來的網頁內容有所疑惑或是不懂的話,建議依序閱讀 [1], [2], [3] 這幾篇網頁。
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
*********************************************************************************
此網頁所用的材料可自行準備,或選用新版本的升級套件
- V2.1 版 { 萬物皆聯網-ESP8266 IoT(Internet of Things)入門學習套件 }
- Arduino UNO + ESP8266 (Wi-Fi) 二合一開發板 ( 可選擇獨立與偕同開發 )
*********************************************************************************
測試接線圖:
測試的線路如下面所示,使用Arduino UNO + ESP8266 (Wi-Fi) 二合一開發板加上 USB 轉 TTL 模組或是線都可以,怎麼使用與上傳程式請看網頁[2]裡面的說明 。
若使用 Arduino 開發板外接 ESP8266,則 ESP8266 連接線路在部落格網頁裡面有,這裡不再另外贅述。
Arduino UNO + ESP8266 (WiFi) 開發板測試接線圖 |
在上一篇,成功的操作 AT 指令控制 ESP8266 建立與中華電信 IoT 智慧聯網大平台 (下面簡稱為 CHT IoT SP ) 的透傳通訊,調用其兩種不同的 RESTful API 協定讀取了設備所有感測器和單一感測器最後一筆的數據。藉由所得到的 Request 發送和 Response 接收的格式,下面選用 "讀取最新一筆感測資料" 協定來撰寫 Arduino (UNO) 的測試程式碼。
下面分為三個部分,每一個部分都有測試影片:
- 以取回 SHT31_Temperature 感測器最後一筆數據為例,展示如何發送 HTTP GET Request 格式與接收 HTTP GET Response 格式資料;只有正確接收到完整 HTTP GET Response 的資料,才能區分出 Response 格式中 headers 和 body 這兩個部分以進行下一步 JSON 字串解析。
- 以讀取 SHT31_Temperature 感測器最後一筆數據為例,展示如何解析 HTTP GET Response 格式裡屬於 body 中的 JSON 字串,並解析出其中的各個欄位值。
- 示範重複讀取並解析由 CHT IoT SP 取回的設備與單一感測器的 HTTP GET Response 的 JSON 字串。
解析 JSON 字串是重點,所以程式碼只說明第二部分。
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 讀取 SHT31_Temperature 最後一筆感測資料 - 原始輸出入資料:
下面的影片很簡單的展示了如何發送 HTTP GET Request headers 字串,讀取在 CHT IoT SP 上 SHT31_Temperature 感測器的資料。
讀取回來的資料符合該協定 HTTP GET Response 的格式;其中,格式中 body 部分才是返回的感測器資訊部分,這是 JSON 格式的字串,主要就是解析這一部分。
完整的輸出入資料如下圖所示。
紅色框是輸出到 CHT IoT SP 的 HTTP GET Request 格式字串;藍色框與粉色框是一次接收到的 HTTP GET Response 格式字串,其中粉色框才是所要求的 SHT31_Temperature 的資料,只不過這一長串文字是 JSON 格式的字串,需要再進一步的解析!
讀取 SHT31_Temperature 最後一筆感測資料 - 原始輸出入資料 |
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 讀取 SHT31_Temperature 最後一筆感測資料 - JSON 字串解析:
結合上面的結果並加入 JSON 字串解析的功能,實際測試的結果如下影片所示。
HTTP GET Request 字串成功發送之後,CHT IoT SP 會回傳 HTTP GET Response 格式的字串。但不是全部回傳的部分都需要處理,只有最後的那一長串 JSON 字串 (屬於 body ) 才要!
類似的解析過程雷同於部落格另一篇網頁 "使用 Arduino IDE 開發 ESP8266 物聯網應用 - 取回 ThingSpeak 特定 Channel 和 Field 最後一筆資料" 。但因為年代久遠,當中所使用的 ArduinoJSON 函式庫經過多年來的精進,已經進入到 V6 beta 版階段 (相信不久就能 release),補正很多缺點與加入許多功能,好用許多!
但有一個重點需要注意:在 ArduinoJSON V6 未真正 Release 之前,下面的程式只能使用 V5.#.# 的版本編譯!
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*
環境設置:
- Software
- Arduino IDE v1.8.5
- Library
- ArduinoJSON v5.13.2
- Hardware (下面兩種型式皆可)
- Arduino UNO + ESP8266 (WiFi) 二合一開發板**
- Arduino 開發板外接 ESP8266 無線模組**
** ESP8266 AT 韌體版本 AT: 1.2.0.0, SDK: v1.5.4.1
/*-/--*-*/*/*/*/***//-*-*-**-*/*-*-/*/*/*-*-/-////--/**/**--**/--///--//**----**//--**//**----***//*-**//*下面的程式碼與影片中使用相同,當中移除一些冗長的註解並採分段說明,使用之前請自行整理。
先看一下主程式的部分;由於 loop() 裡面不需要程式碼,所以只說明 setup() 的部分。
setup
- line 9 ~ 10: 退出 ESP8266 透傳模式並確認 ESP8266 是否連接正確;若發生錯誤,LED 每秒閃爍1 次!
- line 11: 關閉 TCP 連線*
- line 12: 斷開與無線路由器 (AP) 的連接*
- line 16 ~ 17: 建立與 CHT IoT SP 的 TCP Client 透傳通訊;若連線的 AT 指令出現錯誤,LED 每秒閃爍 2 次!
- line 18: 主要執行 HTTP GET Request與讀取 HTTP GET Response 和解析 JSON 字串的函式;這部分留待下面該函式的部分再做說明。
- line 19: LED 常亮,表示正常完成連線、讀取和解析 SHT31_Temperature 感測資料
- line 23: 程式會停在這裡不再往下執行
CHTIoTTCPGetReply_JSONParse_Demo00.ino, (01/05), setup()+loop()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void setup() { Serial.begin( 115200 ); swSerialOutput.begin( 115200 ); delay( 3000 ); pinMode( _builtin_led, OUTPUT ); swSerialOutput.print( F("SoftwareSerial Ready!\r\n") ); if( !exitPassthroughMode() ) ledErrorIndicator( 1 ); closeTCPConnection(); disconnectFromAP(); swSerialOutput.print( F("\r\n>>>>>>>> START <<<<<<<<\r\n") ); swSerialOutput.print( F("-------------------\r\n SHT31_Temperature \r\n-------------------\r\n") ); if( !station_createTCPPassthrough() ) ledErrorIndicator( 2 ); retrieveDataFromCHTIoT(); digitalWrite( _builtin_led, HIGH ); swSerialOutput.print( F(">>>>>>>> END <<<<<<<<\r\n") ); disconnectFromAP(); stopRunning(); } |
程式用到的標頭檔與變數宣告和定義。
CHTIoTTCPGetReply_JSONParse_Demo00.ino, (02/05)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #include <SoftwareSerial.h> #include <ArduinoJson.h> //--** Software Serial **// #define _rxpin 2 #define _txpin 3 SoftwareSerial swSerialOutput( _rxpin, _txpin ); // RX, TX // 如果要輸出一些除錯訊息的話 #define DEBUG #ifdef DEBUG #define dbgOutput( str ) (swSerialOutput.print( str )) #else #define dbgOutput( str ) #endif // 常亮表示 AT 指令執行正常,閃爍就是出現錯誤! #define _builtin_led 13 static String rcv =""; |
checkOK 此處的 checkOK() 函式與 "如何使用 MCU 建立與其他 ESP8266 的 UDP 透傳通訊" 裡用的不同,穩定性高且相對速度快!尤其是對於那些返回行數多的 AT 指令,非常有效且好用,分享給大家!
其他下面幾個一般輔助函式的程式碼,就不再多加說明!
CHTIoTTCPGetReply_JSONParse_Demo00.ino, (03/05), functions()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | bool checkOK( ) { uint8_t i = 0; while( !Serial.find( "OK" ) ) { if( ++i >= 6 ) return false; } return true; } bool exitPassthroughMode() { Serial.println( "AT" ); if( !checkOK() ) { Serial.print( "+++" ); delay( 1000 ); Serial.println( "AT" ); if( !checkOK() ) return false; } return true; } void closeTCPConnection() { Serial.println( "AT+CIPCLOSE" ); checkOK(); } void disconnectFromAP() { Serial.println( "AT+CWQAP" ); checkOK(); } void ledErrorIndicator( uint8_t times ) { static uint16_t offms[] = {900, 400, 250, 150, 100}; while(1) { for( int i = 0; i < times; i++ ) { digitalWrite( _builtin_led, HIGH ); delay( 100 ); digitalWrite( _builtin_led, LOW ); delay( offms[times - 1] ); } delay( 1000 ); } } void stopRunning() { while(1) delay( 1000 ); } |
相信看過前面幾篇網頁的用戶對下面的程式碼不會太陌生,差在改用 TCP 連線而已,所以不再加以贅述!
這裡提醒一點,dbgOutput() 可以用來偵測此處的 AT 指令是否輸出正確。測試沒問題之後就可將程式開頭的 //#define DEBUG 註解掉,加快執行的速度!
CHTIoTTCPGetReply_JSONParse_Demo00.ino, (04/05), station_createTCPPassthrough()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | bool station_createTCPPassthrough() { // station swSerialOutput.print( F("Connecting to CHT IoT SP...") ); dbgOutput( "\r\n" ); // 建立 station Serial.println( "AT+CWMODE_CUR=1" ); // station mode dbgOutput( F("AT+CWMODE_CUR=1\r\n") ); if( !checkOK() ) return false; // 連線到 ROUTER Serial.println( "AT+CWJAP_CUR=\"Proteus-WiFi\",\"asdfghjkl\"" ); dbgOutput( "AT+CWJAP_CUR=\"Proteus-WiFi\",\"asdfghjkl\"\r\n" ); if( !checkOK() ) return false; // 指定 station 的 IP、Gateway 和 Netmask Serial.println( "AT+CIPSTA_CUR=\"192.168.11.11\",\"192.168.11.1\",\"255.255.255.0\"" ); dbgOutput( "AT+CIPSTA_CUR=\"192.168.11.11\",\"192.168.11.1\",\"255.255.255.0\"\r\n" ); if( !checkOK() ) return false; // Establish TCP Transmission // <type>,<remote IP>,<remote port> Serial.println( "AT+CIPSTART=\"TCP\",\"iot.cht.com.tw\",80"); dbgOutput( "AT+CIPSTART=\"TCP\",\"iot.cht.com.tw\",80\r\n"); if( !checkOK() ) return false; // 設定傳輸模式為透傳模式 Serial.println( "AT+CIPMODE=1" ); dbgOutput( "AT+CIPMODE=1\r\n" ); if( !checkOK() ) return false; // 開始傳送資料 Serial.println( "AT+CIPSEND" ); dbgOutput( "AT+CIPSEND\r\n" ); if( !Serial.find( ">" ) ) return false; swSerialOutput.print( "done.\r\n\r\n" ); return true; } |
整個程式最主要的部分,負責 HTTP GET Request 的發送、HTTP GET Response 的接收和 JSON 字串的解析。
retrieveDataFromCHTIoT
- line 5: 發送 HTTP GET Request 字串給 ESP8266 並傳送至 CHT IoT SP
- line 7 ~ 56: 持續等待 CHT IoT SP HTTP GET Response 的回傳,並且處理 JSON 字串的解析
- line 11 ~ 24: 處理 Request headers 的部分
line 12 ~ 17 確認回傳的資料是否是請求成功的回傳,若不是則輸出提示並停止往下執行;line 20 ~ 24 確認 Request headers 部分是否傳送結束,若不是輸出提示並停止往下執行。 - line 26 ~ 51: 接收並處理 Response body 部分,並解析出 JSON 字串裡的各欄位值
line 30 ~ 31 配置 ArduinoJSON 需要的陣列和緩衝的大小;line 34 ~ 38 解析 JSON 字串並確認是否解析成功;line 41 ~ 49 輸出 JSON 字串解析之後的各欄位值。
CHTIoTTCPGetReply_JSONParse_Demo00.ino, (05/05), retrieveDataFromCHTIoT()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | void retrieveDataFromCHTIoT() { swSerialOutput.println( F("Request ->:") ); // RESTful API "讀取最新一筆感測資料" 協定 HTTP GET Request 格式 swSerialOutput.println( F("GET /iot/v1/device/6945661182/sensor/SHT31_Temperature/rawdata HTTP/1.1\r\nHost: iot.cht.com.tw\r\nCK: PK64AFUMECPJ8M2FZ0\r\n") ); Serial.println( "GET /iot/v1/device/6945661182/sensor/SHT31_Temperature/rawdata HTTP/1.1\r\nHost: iot.cht.com.tw\r\nCK: PK64AFUMECPJ8M2FZ0\r\n" ); while(1) { if( Serial.available() ) { char status[32] = {0}; // check HTTP status Serial.readBytesUntil( '\r', status, sizeof(status) ); if( strcmp( status, "HTTP/1.1 200 " ) != 0) { dbgOutput(F("Unexpected response: ")); dbgOutput(status); dbgOutput( "\r\n" ); stopRunning(); } // Skip HTTP headers char endOfHeaders[] = "\r\n\r\n"; if (!Serial.find(endOfHeaders)) { dbgOutput(F("Invalid response")); dbgOutput( "\r\n" ); stopRunning(); } //--** 開始取得從 Serial 回傳的 JSON 字串,並直接解析 **--// //{"id":"SHT31_Temperature","deviceId":"6945661182","time":"2018-08-01T08:20:33.361Z","value":["33.6"]} // Allocate JsonBuffer const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(4) + 100; DynamicJsonBuffer jsonBuffer(capacity); // Parse JSON object JsonObject& root = jsonBuffer.parseObject(Serial); if (!root.success()) { dbgOutput(F("Parsing failed!")); dbgOutput( "\r\n" ); stopRunning(); } // Extract values swSerialOutput.println( F("JSON Parser <- Response:") ); swSerialOutput.print( F("id=") ); swSerialOutput.println(root["id"].as<char*>()); swSerialOutput.print( F("deviceId=") ); swSerialOutput.println(root["deviceId"].as<char*>()); swSerialOutput.print( F("time=") ); swSerialOutput.println(root["time"].as<char*>()); swSerialOutput.print( F("value=") ); swSerialOutput.println(root["value"][0].as<float>()); break; } // if } // while exitPassthroughMode(); // +++ closeTCPConnection(); // AT+CIPCLOSE } // retrieveDataFromCHTIoT() |
完成編譯之後上傳程式執行,可得到跟影片相同的輸出過程與結果。
截取其輸出畫面的結果,粉色框的部分就是上一段 retrieveDataFromCHTIoT() 執行 JSON 字串解析之後的結果
CHTIoTTCPGetReply_JSONParse_Demo00.ino 執行輸出畫面 |
/*--*//**---/*///**---*-*////***--*/*///***----*///--*/*///**--*/*//**--**/*//
* 讀取並解析出設備與單一感測器的欄位數據:
若看懂上一小節的程式碼,那麼接下來下面這個影片中所展示的程式執行過程與結果,應該也不會太難實現!
程式將在連上 CHT IoT 之後,一次性連續完成兩種協定三個讀取的動作;先 "讀取 ( 二合一開發板 ) 設備所有感測器最新一筆感測資料",再來 "讀取 ( SHT31_Temperature ) 最新一筆感測資料",最後 "讀取 ( SHT31_Humidity ) 最新一筆感測資料" 。
結論:
雖然到現在的為止,所談論的部分只侷限在兩個 CHT IoT SP 的 RESTful API 協定中,但是起頭的方法都差不多,都可以使用前篇談及的基本的方法,先行驗證 Request 輸出以及取回 Response 的輸入。有了輸出入的東西之後,就能以本篇的程式碼為基礎,撰寫出屬於自己的解析程式。
知道了怎麼解決讀取數據的問題之後,接下來就來實際玩玩上傳與不一樣的 RESTful API 協定吧!
<< 部落格相關文章 >>
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 07 } - 結合 Arduino + ESP8266 實現 MQTT 主題訂閱與接收
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 06 } - 了解 MQTT 協議,學習如何訂閱 MQTT 主題與接收 MQTT 發佈消息
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 05 } - 結合 ESP8266 發佈 MQTT 消息
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 04 } - 了解 MQTT 協議,學習如何發佈 MQTT 消息
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 03 } - 使用 Arduino + ESP8266 上傳 SHT31 溫溼度數據
- 當 ESP8266 遇上中華電信 IoT 智慧聯網大平台 { 入門 - 01 } - 如何使用 ESP8266 利用 AT 指令取回中華電信 IoT 智慧聯網大平台上的設備感測器數據
- 如何使用 MCU 建立與其他 ESP8266 的 UDP 透傳通訊
- ESP8266 AT 指令下的透傳模式
- 如何使用 AT 指令讓同在 AP+STA 模式下的 ESP8266 互相通訊 ?
- 操控 ESP8266 無線模組 - 經由 AP、STA 和 AP+STA 三種模式,學習 ESP8266 AT 指令
沒有留言:
張貼留言
留言屬名為"Unknown"或"不明"的用戶,大多這樣的留言都會直接被刪除掉,不會得到任何回覆!
發問問題,請描述清楚你(妳)的問題,別人回答前不會想去 "猜" 問題是什麼?
不知道怎麼發問,請看 [公告] 部落格提問須知 - 如何問問題 !