できること

第35回 Arduinoマイコンとしても使える小型WifiモジュールESP-WROOM-02を使ってみる(Arduinoでwifi利用編)

P1210126 (2)

前回はついにESP-WROOM-02をArduinoとして動かすことができました。もうここまで来ればESP-WROOM-02をマスターするまでもう一歩です。今回はArduinoのプログラムでwifi通信を実現して、さまざまなデバイスへの応用を考えてみたいと思います。wifi通信ができて無線化できるとどんなことが便利になるでしょうか?普段不便に思っていることをESP-WROOM-02で無線化できるかどうかを検討したり、実際に触って手を動かしながらアイデアを考えたりしていきましょう。

今回の電子工作レシピ

時間目安:90分
必要なパーツ

 

Arduinoのwifi通信プログラムの基礎をおさえる

まずはじめに、ESP-WROOM-02のArduinoプログラム上でwifi通信をするために、サンプルプログラムを試してみたいと思います。「ファイル」-「スケッチの例」-「ESP8266WIFI」-「WIFIWebServer」を選択します。このサンプルプログラムは、Arduinoでwifi通信するための基本的な処理が記述されています。

 

図1 サンプルスケッチの読み込み

図1 サンプルスケッチの読み込み

 

このサンプルプログラムは、ESP-WROOM-02をサーバーにするプログラムです。プログラムが開始されたら、他の端末からリクエストがあるまで待機して、指定の引数をつけた形でリクエストがくると、処理(このプログラムではLEDを光らせる)を行うような流れになっています。

 

前回使った回路をそのまま使ってテストをしてみたいと思いますので、サンプルプログラムで「2」番ピンが指定されている箇所を「13」番ピンに変更します。

図6 ESP-WROOM-02のLチカ回路

図2 wifiでのLED制御回路

 


/*
 * 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チカの完了です。

 

図3 wifi接続成功

図3 wifi接続成功

図4 スマートフォンからの接続もOK

図4 スマートフォンからの接続もOK

 

プログラムを応用してサーボモーターを制御してみる

次はサーボモーターを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までのリンクが表示されて、それぞれをクリックするとサーボモーターが指定した角度に動くプログラムになっています。

写真1 サーボモーターを制御

写真1 サーボモーターを制御

無事サーボを遠隔で制御できました!

 

クリスマスっぽいものを作ってみる

wifi通信の基本的なことがわかりました。今回はクリスマスが近いということもあるので、クリスマスっぽいデバイスを作ってみます。電子工作×クリスマスとなれば、真っ先に思いつくのはイルミネーションですね。LEDをたくさんつける豪勢なイルミネーションもよいですが、机においてクリスマスを感じられるようなものが良いですよね。ということで、雪だるまをモデリングしてみました。モデリングは第29回でも登場した123d designというモデリングツール(※注:123d designはアプリの配信が停止されてしまったため、現在Fusion360などでモデリングが可能です。)を利用しています。直方体や円柱などの形状を組み合わせながらモデリングができるツールなので、初心者の方も気軽に3Dモデルの作成ができるツールです。

 

図5 雪だるまをモデリング

図5 雪だるまをモデリング

モデリングが完了したら、3Dプリンターで出力してみました(今回手のパーツは小さいためうまく出力できませんでした)。手にとって眺めながらどうしよう、と考えます。

写真2 3Dプリンターで出力した雪だるま

写真2 3Dプリンターで出力した雪だるま

ちょうど、手元にフルカラーLEDがありましたので、このフルカラーLEDとwifi通信を組み合わせて、天気に応じてLEDの色が変わるような卓上デバイスにしてみましょう。

 

デバイスの仕様を考える

いつもどおり、プログラムや回路を作成する前にデバイス全体の構成を考えます。今回の全体の構成はこのようになります。

図5 デバイス全体の構成

図6 デバイス全体の構成

Arduinoプログラムから直接APIに接続してデータを取得して処理を行うこともできますが、Arduinoプログラムの容量が少ないため、今後の拡張も考えてArduinoから外部のサーバー(図:SERVER PROGRAM)を設置してリクエストを行い、外部サーバープログラムがAPIに接続して、JSON形式のデータを取得し、必要なデータだけをArduinoに返すようにします。

 

天気データをAPIから取得する

今回利用するAPIはOpenWeatherMapという登録すればフリーで利用できるAPIを使います。このAPIでは、位置情報や都市名をリクエストにつけてその場所の天気情報を取得することができます。

図6 https://openweathermap.org/

図7 https://openweathermap.org/

 

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です。

図8 ブラウザで確認

図8 ブラウザで確認

フルカラーLEDを光らせる

次に、出力側のフルカラーLEDの使い方をみていきます。フルカラーLEDといっても、基本的にはRGB、赤、緑、青の3つのLEDが一つの基板上にのっているようなものなので、扱いは難しくはありません。

図のように、+と-の組み合わせで各色のLEDが光るようになっていますので、ハンダ付けをして、ブレッドボードに接続できるようにします。

写真3 フルカラーLED

写真3 フルカラーLED

写真3 フルカラーLED

写真4 フルカラーLEDをハンダづけ

 

フルカラーLEDを3つとも光らせれば発行色は白色に近づきますが、各色のLEDがそれぞれ必要とする電圧や電流量が違うため、それぞれ別の抵抗値を回路に加える必要があります。

今回は、赤色は91Ω、緑色は180Ω、青は220Ωにしました。

天気APIからデータを取得したときに下記の天気情報に基づいて色が表示されるようにします。

  • Clear – 晴れ → 赤
  • Clouds – 曇り → 緑
  • Rain – 雨 → 青
  • Snow – 雪 → 水色
breadboard01_2

図7 フルカラーLED制御回路図

 

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");
}

このプログラムでは、動作を確認するために毎回データを取得するようにしていますが、実際の運用では、取得するデータの内容に応じて適宜変更してください。プログラムを起動すると天気データを取得したあとにそのデータに基づいてデバイスが淡く光ります。

写真5 雪だるまが天気に合わせて光る

写真5 雪だるまが天気に合わせて光る

最後、雪だるまに装飾を加えて完成です。

図8 完成!

図7 完成!

※動画はサーバー側をランダムに出力するようにして動作テストを行った模様です。

 

まとめ

今回は天気APIを使って卓上デバイスを作成しましたが、他のAPIや、プログラムと連携すれば、何か知らせたいときにこのデバイスを使って光で伝えたり、スマートフォンと連携したりするなどでもっと面白いデバイスができると思います。次回もESP-WROOM-02を使ってこのデバイスのさらなる応用や別のデバイスを作ってみたいと思います!

 

アバター画像

電子工作や新しいデバイスをこよなく愛するエンジニア。日常生活のちょっとしたことを電子工作で作って試して、おもしろく過ごしたいと日々考えています。

ラズパイと液晶画面で、顔を判別してぴったりの動画を流すデジタルサイネージをつくろう!