ESP-WROOM-02とArduino UNO webからデータを取得する。


過去記事は次の通りです。初めての方は一通り目を通される事をお勧めします。

Arduino UNO + ESP-WROOM-02(ESP8266) Arduino UNO + ESP-WROOM-02(ESP8266)

PHPが返してくるレスポンスから整数にするところまで出来ました。後はArduino UNOでどのような処理を行うのかアイデア次第です。現在のPHPでは毎回同じ値を返してくるだけなので実用性が有りません。そこでwebからなにかしらのデータを取得してみたいと思います。 とりあえず練習として気象庁のサイトから情報を持って来ます。

各種データ・資料」に色々なデータがあります。その中でデータ更新頻度が高い方が面白いので「降水の状況」を使ってみます。 24時間降水量一覧表のページに現在の降水量という項目があります。ここからPHPを使って情報を取り出します。APIが提供されていれば楽ですが今回はあえてwebのhtmlから情報を取り出してみます。この方法ではAPIが提供されていない情報を取り出す事が可能です。ただし、その利用については注意が必要です。 新潟県新潟市の降水量を取り出します。 スクリーンショット 2015-08-30 9.59.25 tableになっていますが、新潟*と記入された隣のセルに降水量が入っています。htmlソースコードを見ると

<tr class="mtx">
<td style="white-space:nowrap">新潟県</td>
<td style="white-space:nowrap">新潟*</td>
<td style="text-align:right;">4.5</td>
<td style="text-align:right;">9.5 ]</td>
<td style="text-align:center;">00:10</td>
<td style="text-align:left;"></td>
<td style="text-align:right;">266</td>
<td style="text-align:center;">1998/08/04</td>
<td style="text-align:right;">266</td>
<td style="text-align:center;">1998/08/04</td>
<td style="text-align:center;">1976年</td>
</tr>

となっています。見やすい様に改行を入れています。 文字列「新潟*」を検索し、その次の「tdの閉じタグ」までの間に降水量が小数点付の数字で入っています。これを取得して返すPHPを作ります。新潟*を置き換えれば全国どこでも好きな所のデータを取得する事ができます。

<?php

mb_language("Japanese");//処理言語の設定
mb_internal_encoding("UTF-8");//文字コードの指定

$url = "http://www.data.jma.go.jp/obd/stats/data/mdrr/pre_rct/alltable/pre24h00.html";

//webページの読み込み
$contents= file_get_contents($url);

//文字コードの変換
$contents_utf = mb_convert_encoding($contents,"UTF-8","auto");

//指定した文字列で囲まれた部分を取り出す。
$startString = '<td style="white-space:nowrap">新潟*</td><td style="text-align:right;">';
$endString = '</td>';

$startPoint = mb_strpos($contents_utf,$startString) ;//$startStringが現れる位置を調べる
$startPoint = $startPoint + mb_strlen($startString);//開始位置
//echo $startPoint;
//echo"
";

$endPoint = mb_strpos($contents_utf,$endString,$startPoint );//$endStringが次に現れる位置を調べる
//echo $endPoint;
//echo"
";

$length = $endPoint - $startPoint;//文字列の長さを求める。
$rainfallString = mb_substr($contents_utf,$startPoint,$length);
echo $rainfallString;
?>

処理の中身についてはコメントを参考にしてください。狙っている文字列がhtmlのソースに一度しか出てこない場合には使える方法です。コメントにしてありますが途中でechoで値を出力しています。これやらないと動かない時にどこでなにが起きているのか分からないので開発中には変数の値はechoで出力してブラウザで確認しましょう。

PHPは/PHP/esp8266/rainfall.phpに設置しました。Arduinoからアクセスするスケッチは次の様になります。

#include "ESP8266.h"
#include <SoftwareSerial.h>

//Arduino UNOとESP8266をシリアルで繋いで通信。
//UNOとESP8266はSoftware Serialで通信。

#define SSID "mkb-home"
#define PASSWORD "matsutaro"
#define HOST_NAME "mkbtm.sakura.ne.jp"
#define HOST_PORT 80

SoftwareSerial mySerial(12, 11); /* RX:12, TX:11 */
ESP8266 wifi(mySerial);
//software serialの速度はESP8266.hで設定

void setup(void)
{
//Serial.begin(9600);
Serial.begin(57600);
Serial.print("setup begin\r\n");

Serial.print("FW Version:");
Serial.println(wifi.getVersion().c_str());

if (wifi.setOprToStationSoftAP()) {
Serial.print("to station + softap ok\r\n");
} else {
Serial.print("to station + softap err\r\n");
}

if (wifi.joinAP(SSID, PASSWORD)) {
Serial.print("Join AP success\r\n");
Serial.print("IP:");
Serial.println( wifi.getLocalIP().c_str());
} else {
Serial.print("Join AP failure\r\n");
}

if (wifi.disableMUX()) {
Serial.print("single ok\r\n");
} else {
Serial.print("single err\r\n");
}

Serial.print("setup end\r\n");
}

void loop(void)
{
uint8_t buffer[512] = {0};

if (wifi.createTCP(HOST_NAME, HOST_PORT)) {
Serial.print("create tcp ok\r\n");
} else {
Serial.print("create tcp err\r\n");
}

char *hello = "GET /PHP/esp8266/rainfall.php HTTP/1.0\r\nHost: mkbtm.jp\r\nUser-Agent: arduino\r\n\r\n";

wifi.send((const uint8_t*)hello, strlen(hello));

String resultCode = "";//サーバからの文字列を入れるための変数

uint32_t len = wifi.recv(buffer, sizeof(buffer), 10000);
if (len > 0) {
for(uint32_t i = 0; i < len; i++) {
resultCode += (char)buffer[i];
}
Serial.println(resultCode);//確認のため出力
//lastIndexOfでresultCodeの最後から改行を探す。
int lastLF = resultCode.lastIndexOf('\n');
//resultCodeの長さを求める。
int resultCodeLength = resultCode.length();

//substringで改行コードの次の文字から最後までを求める。
String resultString = resultCode.substring(lastLF+1, resultCodeLength);
Serial.println(resultString);//確認のため出力
resultString.trim();//念のために前後のスペースを取り除く。無くても可。

float resultValue = resultString.toFloat();//Stringをintに変換

Serial.print("resultValue=");//値の出力
Serial.println(resultValue, 1);
Serial.print("\r");
}

delay(5000);
}

前回のサンプルから特に変更した所はありませんが、最後に小数点付のデータなのでfloatを使い、toFloat()で文字列から数値に変換しています。
さてこの先はどうこのデータを使いましょうか?降水量に応じてLEDを光らせますか?フルカラーLEDで色を変えますか?サーボモータでメータの針を動かしますか?ペルチエ素子で雨量に連動した温度を作り出しますか?7セグのLEDで雨量を表示しますか?雨量に応じて部屋の照明を変化させますか?
なんでしょうね?