# 關於物聯網服務平台 Pachube 與 Cosm
我以為它完全不再提供免費服務, 所以就轉而使用開源的 ThingSpeak. 但今天在翻閱本周要還的這本碁峰的 "實戰數位家庭自動化" :
在第 4, 5 章介紹利用 Xively 所提供的物聯網服務來將設備所取得的感測資料儲存到雲端, 以達到全球存取目的. 我自己買的博碩出版 "Arduino 物聯網專案實作" 這本的第五章也有介紹結合 Xively 與 Nearbus 服務以紀錄太陽能板的電壓變化 :
我在想這兩本書都還蠻新的, 都沒提到說 Xively 要付費才能用. 於是我用 "xively free" 去搜尋, 發現 Xively 有保留給個人開發者免費使用體驗的登入畫面如下 (官網似乎找不到入口, 只找到 Free Trial), 以前都不知道 :
# https://personal.xively.com
但這是登入畫面, 必須先申請帳號才行, 其申請網址如下 (注意, 此頁面有時會出現 Page not found, 只要重新整理幾次就會顯示了) :
# https://personal.xively.com/signup
填寫帳號, email, 以及密碼, 以及國家, 郵區等資料後, 按 Sign Up 鈕即可. 接著必須去收信, 按信裡面的帳號啟動連結即完成帳號啟用 :
啟用同時即登入, 首先按 "+ Add Device" 新增設備 :
這裡我加入一個 Arduino+ESP8266 的溫溼度與亮度的測候站, 輸入 Device Name 與簡單描述, Privacy 勾選 Private Device (除非是要公開讓人讀取才勾 Public), 按 "Add Device" 即新增 :
新增設備後, 頁面右上方便會出現此設備的 Feed ID, 右下方也會有自動產生的金鑰, 這兩項資料是 Arduino 程式與 Xively 網站連線饋送資料所必須, 所以要複製下來備用 :
最後是按 "+Add Channel" 為此 WeatherStation 設備新增資料通道 (Channel), 也就是要傳送的變數 :
我新增了 Temperature, Humidity, 以及 Luminance 三個變數 :
以上便完成 Xively 的設定了. 關於 Xively 的使用方式可參考 :
# Xively Basics Tutorial
接下來便可撰寫 Arduino 程式來向 Xively 饋送感測資料, 可參考 2016/7/8 這篇最後面的程式來修改 :
# 以 Arduino+ESP8266 物聯網模組重作 DHT11 溫溼度實驗
關於光敏電阻則可參考 :
# Arduino 光敏電阻測試
以下測試程式是在我自己用洞洞板焊接的 Arduino Nano+ESP8266 IOT 模組上進行實驗, 電路圖參考 :
# 製作 Arduino Nano + ESP8266 物聯網模組 (四) : 完結篇
向 Xively 物聯網伺服器饋送資料比 ThingSpeak 稍微麻煩一點, 它採用 HTTP 的 PUT 方法, 將要傳送的參數以 JSON 格式呈現; 而 ThingSpeak 則是用 GET 字串來傳送. 在碁峰的 "實戰數位家庭自動化" 這本書第四章 "用 Xively 建置雲端氣象站" 有範例程式, 不過那是以 CC3000 Wifi 晶片函式庫寫的, 不能直接用在 ESP8266, 但是可以從中了解與 Xively 互動的步驟, 參考 :
此 PUT 方法須向 Xively 傳送如下的 HTTP 標頭 :
PUT /v2/feeds/321056143.json HTTP/1.1
Host: api.xively.com
X-ApiKey: cnSMGOi2HMVV5kaHxq6QKSJ9JgvqIBVblxqWZxxxxxxxxksY
Content-Length: 171
第一行中的 json 主檔名就是上面新增設備時所獲得的 FEED ID, 代表此一氣象站設備; 而 X-ApiKey 屬性值為認證金鑰; 最後一行 Content-Length 則為後面要傳送的 HTTP 本體資料的長度 (byte 數), 也就是 JSON 字串的長度, 其內容如下 :
{"version":"1.0.0","datastreams" : [{"id" : "Temperature","current_value" : "26"},
{"id" : "Luminance","current_value" : "58"},
{"id" : "Humidity","current_value" : "72"}]}
可見其資料結構由 version 與 datastream 兩個屬性組成, 其中 datastream 就是我們要傳送的參數集合, 參數名稱寫在 id 屬性, 而參數值則寫在 current_value 屬性中. 完整程式如下 :
#include <SoftwareSerial.h>
#define DEBUG true
#include "DHT.h"
#define DHTPIN 6
#define DHTTYPE DHT11
SoftwareSerial esp8266(7,8); //(RX,TX)
DHT dht(DHTPIN, DHTTYPE); // Initialize DHT sensor
String feed_id="321056143"; //Xively WeatherStation feed ID
String api_key="cnSMGOi2HMVV5kaHxq6QKSJ9JgvqIBVblxqWZxxxxxxxxksY"; //Xively API Write Key
void setup() {
Serial.begin(9600);
esp8266.begin(9600);
sendData("AT+RST\r\n",2000,DEBUG); // reset ESP8266
sendData("AT+GMR\r\n",1000,DEBUG);
delay(3000); //wait for wifi connection to get local ip
sendData("AT+CIFSR\r\n",1000,DEBUG); //get ip address
}
void loop() {
float Humidity=dht.readHumidity(); //get humidity from DHT11
float Temperature=dht.readTemperature(); //get temperature (C) from DHT11
int cds=analogRead(A0); //get cds voltage (0~5V to 0~1023 dark)
int Luminance=100-map(cds,0,1023,0,100); //map 0~1023(dark) to 0(dark)~100%
Serial.print("Temperature=");
Serial.println(Temperature);
Serial.print("Humidity=");
Serial.println(Humidity);
Serial.print("Luminance=");
Serial.println(Luminance);
//create data string to Xively
String json=String("") + "{\"version\":\"1.0.0\",\"datastreams\" : " +
"[ {\"id\" : \"Temperature\",\"current_value\" : \"" +
String((int)Temperature) + "\"}," +
"{\"id\" : \"Luminance\",\"current_value\" : \"" +
String(Luminance) + "\"}," +
"{\"id\" : \"Humidity\",\"current_value\" : \"" +
String((int)Humidity) + "\"}]}";
String head="PUT /v2/feeds/" + String(feed_id) + ".json HTTP/1.1\r\n" +
"Host: api.xively.com\r\n" +
"X-ApiKey: " + String(api_key) + "\r\n" +
"Content-Length: " + json.length() + "\r\n\r\n";
Serial.println(head);
String cmd="AT+CIPSTART=\"TCP\",\"api.xively.com\",80\r\n";
sendData(cmd, 1000, DEBUG);
cmd="AT+CIPSEND=" + (String)(head.length() + json.length()) + "\r\n";
sendData(cmd,1000,DEBUG);
sendData(head, 1000, DEBUG);
sendData(json, 1000, DEBUG);
sendData("AT+CIPCLOSE\r\n",1000,DEBUG); //close session
delay(5000);
}
String sendData(String command, const int timeout, boolean debug) {
String response="";
esp8266.print(command); // send the read character to the esp8266
long int time=millis();
while ((time+timeout) > millis()) {
while(esp8266.available()) {
// The esp has data so display its output to the serial window
char c=esp8266.read(); // read the next character.
response += c;
}
}
if (debug) {Serial.print(response);}
return response;
}
在這個程式中, 我們從 D0 腳讀取 DHT11 所送出的溫溼度資料; 從 A0 腳讀入光敏電阻的電壓, 然後換算成 0~100% 的光度值. 在 HTTP 協定部分, 我們將 PUT 方法的 HTTP 格式字串分成標頭 (head) 與本體 (json), 先用 AT+CIPSEND 告訴 ESP8266 總共要傳遞多少字元資料 (head 加 json 長度), 然後分兩次先後將head 與 json 傳送出去. JSON 資料的屬性與值必須用雙引號括起來, 所以都用倒斜線來跳脫 (Escape).注意, 在製作 json 字串時, 必須先用 String() 函數產生字串物件, 以避免產生 invalid operands of type 錯誤, 參考 :
# Error: invalid operands of types ‘const char [35]’ and ‘const char [2]’ to binary ‘operator+’
此程式編譯後記憶體耗用情形 :
草稿碼使用了 9,896 bytes (32%) 的程式儲存空間。上限為 30,720 bytes。
全域變數使用了 799 bytes (39%) 的動態記憶體,剩餘 1,249 bytes 給區域變數。上限為 2,048 bytes 。
程式上傳後登入 Xively 網站便可看到各通道資料隨時間變化的圖形 :
# https://personal.xively.com
或在下列網址填入此設備的 PRODUCT ID:
# https://personal.xively.com/develop/PRODUCT_ID
每個通道圖形底下有一個時鐘圖形, 點一下可以更改時間軸單位. Arduino 每提出一次要求, 右邊的 Request Log 新增一筆 :
點一下 feed 就會顯示該次要求的內容 :
序列埠監控視窗擷取訊息如下 :
Temperature=28.00
Humidity=88.00
Luminance=81
PUT /v2/feeds/321056143.json HTTP/1.1
Host: api.xively.com
X-ApiKey: cnSMGOi2HMVV5kaHxq6QKSJ9JgvqIBVblxqWZbPebWRnLksY
Content-Length: 171
AT+CIPSTART="TCP","api.xively.com",80
OK
Linked
AT+CIPSEND=315
< PUT /v2/feeds/321056143.json HTTP/1.1
Host: api.xively.com
X-Ap{"version":"1.0.0","datastreams" : [ {"id" : "Temperature","cur
SEND OK
+IPD,251:HTTP/1.1 200 OK
Date: Sun, 14 Aug 2016 07:01:52 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 0
Connection: keep-alive
X-Request-Id: fab66cbb2e205fcd63e2ee50150edefc40ea5151
Cache-Control:AT+CIPCLOSE
OK
Unlink
參考 :
# vindolin/wifisensor.ino (ESP8266 範例程式)
# https://github.com/openhomeautomation/arduino-home-automation/tree/master/chapter4
# https://personal.xively.com/testdrive
# Python x Arduino物聯網整合開發實戰
沒有留言:
張貼留言