前回、ESP8266でキャラクタ液晶を制御できましたので、ESP8266ならではのWiFi機能を使い、インターネットから情報を取得して表示させてみます。
何か動的な情報で、16字×2行のアルファベットで表示できるもの、ということで、最近動きの慌しい為替レートを表示させてみることにしました。
今回は、回路は前回と全く同じです。
為替レートの情報は、
Foreign exchange rates and currency conversion JSON API
から取得することにしました。
このサイトでは、各種通貨の為替レートをJSON形式で取得できます。
他にも同様のサイトはあるのですが、最近のWebサービスではユーザー登録してAPI Keyを発行してもらう必要があるものがほとんどで、ちょっと実験的に試すために使うにはやや面倒です。
上記のサイトは、一切事前の準備なしに、URLを叩くだけでデータをもらえます。
(その代わり、データの更新頻度はあまり高くないようです。)
ドル円レートの情報を取得する場合、URLは以下のようになります。
(リンクを直接クリックするとエラーになりますので、ブラウザのURL欄へコピー&ペーストしてください。)
http://api.fixer.io/latest?base=USD&symbols=JPY
これに対する応答は以下のような形式になります。
{"base":"USD","date":"2015-08-28","rates":{"JPY":120.84}}
非常にシンプルですね。
なおJSON形式については以下を参照してください。
今回は、ESP8266から上記のURLにアクセスして、取得したJSONデータを解析(パース)してキャラクタ液晶に表示します。
JSON形式の文字列のパーサは、ArduinoJsonというライブラリを使用しました。
ライブラリの追加の仕方は以前紹介した通りです。
ちなみに、このライブラリの作者の方のブログが以下にあります。
なお、私は試していませんが、これ以外にArduinoで使えるJSONパーサのライブラリとしては、aJsonというものもあるようです(以下のリンク)。
WiFi関連の処理は、もともとESP8266のArduino対応ライブラリに含まれています。
TCP/IPやDNSもサポートされています。
TCP/IP、特にTCPの実装は大変ですので、すべて実装済みというのは大変ありがたいことです。
HTTPプロトコルは、今回は最低限の実装だけを行います。
HTTPは状態遷移がないので、エラー処理等を行わないのであればプロトコル自体は簡単です。
例えば
http://host.domain/dir/file
というURLにアクセスする際のサーバとクライアントのやり取りは、
(1)クライアントからhost.domainの80番ポートにTCPで接続
(2)以下をサーバへ送信
GET /dir/file HTTP/1.1 Host: host.domain Connection: close (空の行)
(3)サーバから以下の形式で応答が返ってくる(正常処理の場合)
HTTP/1.1 200 OK (いろいろなHTTPヘッダ) (空の行) 要求されたデータ
(4)サーバから通信が切断される
という流れになります。
スケッチファイルは以下の通りです。
ST7032ライブラリは、前回説明したように修正が必要です。
また、WIFI_SSIDとWIFI_PSKは、ご自身のWIFIのSSIDとパスワードに変更してください。
#include <ESP8266WiFi.h> #include <Wire.h> #include <ST7032.h> #include <ArduinoJson.h> #define WIFI_SSID "*************" #define WIFI_PSK "*************" #define DEST_HOST "api.fixer.io" #define DEST_PORT 80 #define DEST_URL "/latest?base=USD&symbols=JPY" //sample json data used in this sketch // {"base":"USD","date":"2015-08-28","rates":{"JPY":120.84}} ST7032 lcd; void setup() { const int BUFFER_SIZE = JSON_OBJECT_SIZE(4) + JSON_ARRAY_SIZE(1); StaticJsonBuffer<BUFFER_SIZE> jsonBuffer; lcd.begin(16, 2); lcd.setContrast(40); Serial.begin(115200); Serial.println(""); delay(10); WiFi.begin(WIFI_SSID, WIFI_PSK); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.println(""); WiFiClient client; String line; if (!client.connect(DEST_HOST, DEST_PORT)) { Serial.println("connection failed"); return; } client.print(String("GET ") + DEST_URL + " HTTP/1.1\r\n" + "Host: " + DEST_HOST + "\r\n" + "Connection: close\r\n\r\n"); delay(10); //get rid of the HTTP headers while(client.available()){ line = client.readStringUntil('\r'); Serial.print(line); line.trim(); if (line.length() == 0) { break; } } //get http content String buffer=""; while(client.available()){ line = client.readStringUntil('\r'); line.trim(); buffer.concat(line); } //parse json data char json[buffer.length() + 1]; buffer.toCharArray(json, sizeof(json)); Serial.println(json); JsonObject& root = jsonBuffer.parseObject(json); if (!root.success()) { Serial.println("parseObject() failed"); return; } const char* date = root["date"]; Serial.println(date); const char* base = root["base"]; Serial.println(base); JsonObject& rates = root["rates"]; rates.printTo(Serial); Serial.println(); const char* rate = rates["JPY"]; Serial.println(rate); Serial.println(); Serial.println("closing connection"); lcd.setCursor(0, 0); lcd.print(date); lcd.setCursor(0, 1); lcd.print("JPY/"); lcd.print(base); lcd.print(": "); lcd.print(rate); } void loop() { }
データを一度取得してLCDに表示するだけですので、すべての処理はsetup()の中で行っています。
HTTPヘッダは、内容を確認せずに読み飛ばすだけで、サーバからエラーが返ってきても対応はしません。
デバッグ用に、シリアルポートにいろいろ出力していますが、参考までにその出力例を以下に示します。
.... WiFi connected IP address: 192.168.0.106 HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) Date: Sat, 29 Aug 2015 15:44:10 GMT Content-Type: application/json Content-Length: 57 Connection: close Status: 200 OK X-Content-Type-Options: nosniff {"base":"USD","date":"2015-08-28","rates":{"JPY":120.84}} 2015-08-28 USD {"JPY":120.84} 120.84 closing connection
コメント