前回はついにESP-WROOM-02をArduinoとして動かすことができました。もうここまで来ればESP-WROOM-02をマスターするまでもう一歩です。今回はArduinoのプログラムでwifi通信を実現して、さまざまなデバイスへの応用を考えてみたいと思います。wifi通信ができて無線化できるとどんなことが便利になるでしょうか?普段不便に思っていることをESP-WROOM-02で無線化できるかどうかを検討したり、実際に触って手を動かしながらアイデアを考えたりしていきましょう。
今回の電子工作レシピ
時間目安:90分
必要なパーツ
- ESP-WROOM-02開発ボード https://www.switch-science.com/catalog/2500/
- ブレッドボード https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4D6P
- LED http://akizukidenshi.com/catalog/g/gI-11577/
- 抵抗器 220Ω/180Ω/91Ω http://akizukidenshi.com/catalog/g/gR-07808/
- フルカラーLED http://akizukidenshi.com/catalog/g/gI-03745/
Arduinoのwifi通信プログラムの基礎をおさえる
まずはじめに、ESP-WROOM-02のArduinoプログラム上でwifi通信をするために、サンプルプログラムを試してみたいと思います。「ファイル」-「スケッチの例」-「ESP8266WIFI」-「WIFIWebServer」を選択します。このサンプルプログラムは、Arduinoでwifi通信するための基本的な処理が記述されています。
このサンプルプログラムは、ESP-WROOM-02をサーバーにするプログラムです。プログラムが開始されたら、他の端末からリクエストがあるまで待機して、指定の引数をつけた形でリクエストがくると、処理(このプログラムではLEDを光らせる)を行うような流れになっています。
前回使った回路をそのまま使ってテストをしてみたいと思いますので、サンプルプログラムで「2」番ピンが指定されている箇所を「13」番ピンに変更します。
/* * This sketch demonstrates how to set up a simple HTTP-like server. * The server will set a GPIO pin depending on the request * http://server_ip/gpio/0 will set the GPIO2 low, * http://server_ip/gpio/1 will set the GPIO2 high * server_ip is the IP address of the ESP8266 module, will be * printed to Serial when the module is connected. */ #include <ESP8266WiFi.h> #include <Servo.h> const char *ssid = "ここには無線ルーターのSSIDを記述"; const char *password = "ここには無線ルーターのパスワードを記述"; // Create an instance of the server // specify the port to listen on as an argument WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); // prepare GPIO2 pinMode(2, OUTPUT); digitalWrite(2, 0); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started"); // Print the IP address Serial.println(WiFi.localIP()); } void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; } // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); } // Read the first line of the request String req = client.readStringUntil('\r'); Serial.println(req); client.flush(); // Match the request int val; if (req.indexOf("/gpio/0") != -1) val = 0; else if (req.indexOf("/gpio/1") != -1) val = 1; else { Serial.println("invalid request"); client.stop(); return; } // Set GPIO2 according to the request digitalWrite(2, val); client.flush(); // Prepare the response String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now "; s += (val)?"high":"low"; s += "</html>\n"; // Send the response to the client client.print(s); delay(1); Serial.println("Client disonnected"); // The client will actually be disconnected // when the function returns and 'client' object is detroyed }
プログラムを起動するとルーターに接続を試みて、成功するとシリアルモニターにIPアドレスなどが表示されるので、そのIPアドレスに対してブラウザからアクセスしてみます。/gpio/1に接続した場合は、LEDが点灯、/gpio/0に接続するとLEDが消灯されれば、無事wifi通信を通じて、Lチカの完了です。
プログラムを応用してサーボモーターを制御してみる
次はサーボモーターをwifiを通じて動かしてみます。サーボモーターも基本はLEDと同じになります。LEDのプログラムに少し変更を加えてブラウザでアクセスした際のHTMLも少しだけ手を加えてみます。
ESP-WROOM-02:サーボモーター動作プログラム
#include <ESP8266WiFi.h> #include <Servo.h> const char *ssid = "ここには無線ルーターのSSIDを記述"; const char *password = "ここには無線ルーターのパスワードを記述"; Servo myservo; WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); server.begin(); Serial.println("Server started"); Serial.println(WiFi.localIP()); myservo.attach(2); } void loop() { WiFiClient client = server.available(); if (!client) { return; } Serial.println("new client"); while(!client.available()){ delay(1); } String req = client.readStringUntil('\r'); Serial.println(req); client.flush(); // Match the request int val; if (req.indexOf("/gpio/0") != -1){ val = 0; } else if (req.indexOf("/gpio/30") != -1){ val = 30; } else if (req.indexOf("/gpio/60") != -1){ val = 60; } else if (req.indexOf("/gpio/90") != -1){ val = 90; } else if (req.indexOf("/gpio/120") != -1){ val = 120; } else if (req.indexOf("/gpio/150") != -1){ val = 150; } else { Serial.print("REQ:"); Serial.println(req); Serial.println("invalid request"); client.stop(); return; } myservo.write(val); client.flush(); String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now "; s += (val)?"high":"low"; s += "<ul>"; s += "<li><a href='/gpio/0/'>0</a></li>\n"; s += "<li><a href='/gpio/30/'>30</a></li>\n"; s += "<li><a href='/gpio/60/'>60</a></li>\n"; s += "<li><a href='/gpio/90/'>90</a></li>\n"; s += "<li><a href='/gpio/120/'>120</a></li>\n"; s += "<li><a href='/gpio/150/'>150</a></li>\n"; s += "</ul>\n"; s += "</html>\n"; client.print(s); delay(1); Serial.println("Client disonnected"); }
このプログラムでは、ブラウザに0~150までのリンクが表示されて、それぞれをクリックするとサーボモーターが指定した角度に動くプログラムになっています。
無事サーボを遠隔で制御できました!
クリスマスっぽいものを作ってみる
wifi通信の基本的なことがわかりました。今回はクリスマスが近いということもあるので、クリスマスっぽいデバイスを作ってみます。電子工作×クリスマスとなれば、真っ先に思いつくのはイルミネーションですね。LEDをたくさんつける豪勢なイルミネーションもよいですが、机においてクリスマスを感じられるようなものが良いですよね。ということで、雪だるまをモデリングしてみました。モデリングは第29回でも登場した123d designというモデリングツール(※注:123d designはアプリの配信が停止されてしまったため、現在Fusion360などでモデリングが可能です。)を利用しています。直方体や円柱などの形状を組み合わせながらモデリングができるツールなので、初心者の方も気軽に3Dモデルの作成ができるツールです。
モデリングが完了したら、3Dプリンターで出力してみました(今回手のパーツは小さいためうまく出力できませんでした)。手にとって眺めながらどうしよう、と考えます。
ちょうど、手元にフルカラーLEDがありましたので、このフルカラーLEDとwifi通信を組み合わせて、天気に応じてLEDの色が変わるような卓上デバイスにしてみましょう。
デバイスの仕様を考える
いつもどおり、プログラムや回路を作成する前にデバイス全体の構成を考えます。今回の全体の構成はこのようになります。
Arduinoプログラムから直接APIに接続してデータを取得して処理を行うこともできますが、Arduinoプログラムの容量が少ないため、今後の拡張も考えてArduinoから外部のサーバー(図:SERVER PROGRAM)を設置してリクエストを行い、外部サーバープログラムがAPIに接続して、JSON形式のデータを取得し、必要なデータだけをArduinoに返すようにします。
天気データをAPIから取得する
今回利用するAPIはOpenWeatherMapという登録すればフリーで利用できるAPIを使います。このAPIでは、位置情報や都市名をリクエストにつけてその場所の天気情報を取得することができます。
APIに接続する外部サーバーのプログラムはPHPで作成します。下記のプログラムを用いて、country-国、city-年、appid-APIキーを引数にして、天気情報を取得できるプログラムになります。このプログラムをPHPが動く環境に設置して動作を確認します。
外部サーバープログラム(PHP):天気APIからデータを取得
<?php $country = htmlspecialchars($_GET["country"], ENT_QUOTES, 'UTF-8'); $city = htmlspecialchars($_GET["city"], ENT_QUOTES, 'UTF-8'); $appid = htmlspecialchars($_GET["appid"], ENT_QUOTES, 'UTF-8'); $jsonAry = json_decode(file_get_contents("https://api.openweathermap.org/data/2.5/weather?q=".$city.",".$country."&APPID=".$appid)); if(isset($jsonAry->weather)){ echo $jsonAry->weather[0]->main; } else{ echo "no result"; }
プログラムをブラウザでアクセスすると指定した都市の天気情報が表示されればOKです。
フルカラーLEDを光らせる
次に、出力側のフルカラーLEDの使い方をみていきます。フルカラーLEDといっても、基本的にはRGB、赤、緑、青の3つのLEDが一つの基板上にのっているようなものなので、扱いは難しくはありません。
図のように、+と-の組み合わせで各色のLEDが光るようになっていますので、ハンダ付けをして、ブレッドボードに接続できるようにします。
フルカラーLEDを3つとも光らせれば発行色は白色に近づきますが、各色のLEDがそれぞれ必要とする電圧や電流量が違うため、それぞれ別の抵抗値を回路に加える必要があります。
今回は、赤色は91Ω、緑色は180Ω、青は220Ωにしました。
天気APIからデータを取得したときに下記の天気情報に基づいて色が表示されるようにします。
- Clear – 晴れ → 赤
- Clouds – 曇り → 緑
- Rain – 雨 → 青
- Snow – 雪 → 水色
ESP-WROOM-02:天気に応じて光が変わるプログラム
#include <ESP8266WiFi.h> const char *ssid = "無線ルーターのアクセスポイント名"; const char *password = "[無線ルーターのパスワード]"; const char* host = "[プログラムを設置した外部サーバーホスト名]"; const char* appid = "[APIキーを設定]"; //OnlineWeatherMapで登録したAPPID const char* city = "Tokyo"; //都市を選択 const char* country = "jp"; //国を選択 int color[3] = {255,255,255}; int colorPin[3] = {11,12,13}; void setup() { Serial.begin(115200); delay(10); Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } int value = 0; void loop() { delay(1000); ++value; Serial.print("connecting to "); Serial.println(host); WiFiClient client; const int httpPort = 80; if (!client.connect(host, httpPort)) { Serial.println("connection failed"); return; } String url = "/sample/esp-wroom-02/weather.php"; url += "?appid="; url += appid; url += "&country="; url += country; url += "&city="; url += city; Serial.print("Requesting URL: "); Serial.println(url); client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); delay(1000); while(client.available()){ String line = client.readStringUntil('\r'); line.trim(); if(line.equals("Clouds")){ color[0] = 255; color[1] = 0; color[2] = 0; } else if(line.equals("Clear")){ color[0] = 0; color[1] = 0; color[2] = 255; } else if(line.equals("Rain")){ color[0] = 0; color[1] = 255; color[2] = 0; } else if(line.equals("Snow")){ color[0] = 55; color[1] = 128; color[2] = 255; } Serial.println(line); } for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) { for(int cp = 0; cp < 3; cp++){ float ledValue = color[cp] / 255; ledValue = ledValue * fadeValue; Serial.print("cp:"); Serial.print(colorPin[cp]); Serial.print(" ledValue:"); Serial.println((int)ledValue); analogWrite(colorPin[cp], (int)ledValue); } delay(100); } for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) { for(int cp = 0; cp < 3; cp++){ float ledValue = color[cp] / 255; ledValue = ledValue * fadeValue; analogWrite(colorPin[cp], (int)ledValue); } delay(100); } Serial.println(); Serial.println("closing connection"); }
このプログラムでは、動作を確認するために毎回データを取得するようにしていますが、実際の運用では、取得するデータの内容に応じて適宜変更してください。プログラムを起動すると天気データを取得したあとにそのデータに基づいてデバイスが淡く光ります。
最後、雪だるまに装飾を加えて完成です。
※動画はサーバー側をランダムに出力するようにして動作テストを行った模様です。
まとめ
今回は天気APIを使って卓上デバイスを作成しましたが、他のAPIや、プログラムと連携すれば、何か知らせたいときにこのデバイスを使って光で伝えたり、スマートフォンと連携したりするなどでもっと面白いデバイスができると思います。次回もESP-WROOM-02を使ってこのデバイスのさらなる応用や別のデバイスを作ってみたいと思います!