2019年10月15日火曜日

ESP-WROOOM-02単体でWebサーバーを構築

ESP-WROOOM-02単体でWebサーバーを構築してみます。

ESP8266用の環境構築、WiFi接続、Webサーバー構築の流れで進めます。

ここでの内容は、概ねESP8266 Arduino Coreからの和訳、抜粋、編集したものなので、詳細はそちらでご確認ください。

Arduino IDEでの環境構築

まずは、ESP8266での開発環境を構築します。

正直なところ、ライブラリをインストールするとメニュー表示がゴチャゴチャしてきて好きではないのですが、ボードマネージャで管理している限りではでアンインストール出来るので我慢して進めます。

  • Arduinoを起動し、環境設定ウィンドウを開きます。 Windows: ファイルで開くプルダウンから以下を選択。
    • 環境設定 Ctrl+カンマ
    Mac: Arduinoで開くプルダウンから以下を選択。
    • Preferences... ⌘,
  • [追加のボードマネージャのURL:]フィールドに下記のアドレスを入力。
    ドマネージャのURL : https://arduino.esp8266.com/stable/package_esp8266com_index.json
    複数のURLをカンマで区切って追加できます。
  • [ツール] > [ボード:]メニューから[ボードマネージャ...]を開き、下記のesp8266プラットフォームを見つけて選択。
    esp8266 by ESP8266 Community バージョン2.5.2
    このパッケージに含まれるボード :
    Generic ESP8266 Module, Generic ESP8285 Module, ESPDuino (ESP-13 Module), Adafru
    XinaBox CW01, ESPresso Lite 1.0, ESPresso Lite 2.0, Phoenix 2.0, NodeMCU 0.9 (ES
    (ESP-12E Module), Olimex MOD-WIFI-ESP8266(-DEV), SparkFun ESP8266 Thing, SparkFu
    210, LOLIN(WEMOS) D1 R2 & mini, LOLIN(WEMOS) D1 mini Pro, LOLIN(WEMOS) D1 mini L
    Module), ThaiEasyElec's ESPino, WifInfo, Arduino, 4D Systems gen4 IoD Range, Dig
    Speed Wio Link, ESPectro, Core.
    Online help
    More info
    
    
  • 必要なバージョンをから選択します。
  • をクリックします。
  • インストールが完了したら、を押してボードマネージャウィンドウを閉じます。
  • インストール後、[ツール] > [ボード]メニューから"ESP8266ボード"を選択します。 ここでは、Generic ESP8266 Moduleを選択。
    • ESP8266 Boards(2.5.2)
    • Generic ESP8266 Module
    • Generic ESP8285 Module
    • Generic ESP8285 Module
    • ESPDuino(ESP-12Module)
    • Adafruit Feather HUZZAH ESP8266
    • Invert One
  • Generic ESP8266 Moduleを選択すると、以下のように設定項目が変化します。 Flash Size:(赤枠の箇所)を使用しているESP8266に合わせて変更。
    • ボード:"Generic ESP8266 Module" ⟩
    • Upload Speed: "115200" ⟩
    • CPU Frequency: "80 MHz" ⟩
    • Crystal Frequency: "26 MHz" ⟩
    • Flash Size: "4M(1M SPIFFS)" ⟩
    • Flash Mode: "DOUT(compatible)" ⟩
    • Flash Frequency: "40MHz" ⟩
    • Reset Method: "ck" ⟩
    • Debug port: "Disabled" ⟩
    • Debug Level: "なし" ⟩
    • IwIP Variant: "v2 Lower Memory" ⟩
    • VTables: "Flash" ⟩
    • Exceptions: "Disabled" ⟩
    • Builtin Led: "2" ⟩
    • Erase Flash: "Only Sketch" ⟩
    • Espressif FW: "nonos-sdk 2.2.1 (legacy)" ⟩
    • SSL Support: "All SSL ciphers (most compatible)" ⟩
    ここで使用しているWi-Fiモジュール ESP-WROOM-02 DIP化キットは、"Flash Size"が4Mbyteなので、SPIFFS(SPI Flash File System)を1〜3Mbyteで任意に設定出来ます。 各自の環境に併せて設定して下さい。
以上で環境設定は完了。

WiFiの設定

ESP-WROOM-02開発環境も整ったので、ESP8266WiFiライブラリのドキュメントを参考にWiFiの設定を進めます。ESP8266WiFiライブラリは、既に販売終了となってしまったARDUINO WIFI SHIELD用純正ライブラリの拡張版だそうで、基本部分のコマンドに関してはArduino公式の解説を参照しても良さそうです。

Quick Startに記載されているWiFi接続のスケッチを若干修正したサンプル。
#include <ESP8266WiFi.h>

void setup() {
	Serial.begin(9600);
	Serial.println();

	WiFi.begin("SSID", "PASSWORD");

	Serial.print("Connecting");
	while(WiFi.status() != WL_CONNECTED) {
		delay(500);
		Serial.print(".");
	}
	Serial.println(" connected");

	Serial.print("Connected, IP address: ");
	Serial.println(WiFi.localIP());
}

void loop() {
}
以下は、上記コードで使用しているESP8266WiFiライブラリの3つのメソッド。
詳細は、Station Classを参照。

WiFi.begin()

説明

ステーションモードを有効にし、フラッシュメモリに保存された設定に基づいて、最後に使用したアクセスポイントに接続します。

構文

WiFi.begin(ssid, password, channel, bssid, connect)

パラメータ

  • ssid接続したいアクセスポイントのSSIDを含む文字列、最大32文字
  • password アクセスポイントのパスワード。8〜64文字以下の文字列
  • channel APのチャネル。特定チャネルを使用して操作する場合は、省略可
  • bssid APのMACアドレス。このパラメーターもオプションです
  • connect falseに設定されている場合、他のパラメーターを保存する

WiFi.status()

説明

WiFiの接続状態を返します。

構文

WiFi.status();

パラメータ

なし

戻り値

wl_definitions.hで以下の様に定義された列挙体の該当値が返ります。
typedef enum {
	WL_NO_SHIELD			= 255,	// WiFi Shieldライブラリと互換
	WL_IDLE_STATUS		= 0,	// Wi-Fiがステータスを切り替えるプロセス中の戻り値
	WL_NO_SSID_AVAIL		= 1,	// 設定されたSSIDが利用できない場合の戻り値
	WL_SCAN_COMPLETED	= 2,	// スキャン完了時の戻り値
	WL_CONNECTED			= 3,	// WiFi接続が確立された後の戻り値
	WL_CONNECT_FAILED	= 4,	// 接続が失敗したときの戻り値
	WL_CONNECTION_LOST	= 5,	// 接続が失われたときの戻り値
	WL_DISCONNECTED		= 6	// ステーションモードに未設定の場合の戻り値
} wl_status_t;
サンプルスケッチで該当する箇所を抜き出してみた。
	while(WiFi.status() != WL_CONNECTED) {
	}
WL_CONNECTEDは、'3'を表しているので、
	while(WiFi.status() != 3) {
	}
と書いても動く。

WiFi.localIP()

説明

ステーションモードで本機のIPアドレスを取得する。

構文

WiFi.localIP()

パラメータ

なし

戻り値

返される値のタイプはIPAddressです。
実際にスケッチをESP-WROOM-02へ書き込んで実行すると、シリアルモニタには以下のように表示されます。
Connecting.. connected
Connected, IP address: XXX.XXX.XXX.XXX
WiFiの接続が確認出来たので、Webサーバーを動かしてみます。

ESP-WROOM-02をWebサーバーにする

ESP8266WiFi.hには、
#include "IPAddress.h"

#include "ESP8266WiFiType.h"
#include "ESP8266WiFiSTA.h"
#include "ESP8266WiFiAP.h"
#include "ESP8266WiFiScan.h"
#include "ESP8266WiFiGeneric.h"

#include "WiFiClient.h"
#include "WiFiServer.h"
#include "WiFiServerSecure.h"
#include "WiFiClientSecure.h"
#include "BearSSLHelpers.h"
#include "CertStoreBearSSL.h"
のように、WiFiServer.hやWiFiClient.hが含まれているので、そのままでもWebサーバーの起動が可能です。ただし、ESP8266用の拡張機能が使えなくなってしまうので、下記の書式で素直にESP8266WebServer.hも組み込むのがベストです。
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
ここでは、本家のコチラESP8266WiFi.hのみでWebサーバーを稼働させている例が記載されていたので、ESP8266WebServer.hとの比較も兼ねて試してみたいと思います。

WiFiの設定で使用したスケッチに赤枠で囲んだ箇所を追加しています。
#include <ESP8266WiFi.h>

	WiFiServer server(80);	// サーバー オブジェクトを作成

void setup() {
	Serial.begin(9600);
	Serial.println();

	WiFi.begin("SSID", "PASSWORD");

	Serial.print("Connecting");
	while(WiFi.status() != WL_CONNECTED) {
		delay(500);
		Serial.print(".");
	}
	Serial.println(" connected");

	// サーバーの起動とIPアドレスの表示
server.begin();
Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}

// クライアント(Webブラウザ)に送信するWebページを準備する
//	Webページのコンテンツを含むStringクラス変数を返す短い関数prepareHtmlPage()を作成。
//	この変数をサーバーに引き渡すことで、結果がクライアントに反映されます。
String prepareHtmlPage() {
	String htmlPage = 
	String(	"HTTP/1.1 200 OK\r\n") +
			// 種類と提供方法をクライアントに通知するためのヘッダ部分
			"Content-Type: text/html\r\n" +
			"Connection: close\r\n" +	// 応答が完了すると、接続は閉じられます
			"Refresh: 5\r\n" +			// 5秒ごとに自動的にページを更新する
			"\r\n" +
			// HTMLドキュメントタイプとドキュメントの内容を含む開始終了を示す部分
			"<!DOCTYPE HTML>" +
			"<html>" +
			"Analog input:  " + String(analogRead(A0)) +	// ESPのアナログ入力値を取得・表示
			"</html>" +
			"\r\n";
	return htmlPage;
}

void loop() {
	WiFiClient client = server.available();
// クライアント(Webブラウザ)が接続するのを待機
if (client) {
	Serial.println("\n[Client connected]");
	while (client.connected()) {
		// クライアント(Webブラウザ)がリクエストしているものを1行ずつ読み取る
		if (client.available()) {
			String line = client.readStringUntil('\r');
			Serial.print(line);
			// クライアントのリクエストが終了するのを待ちます
			if (line.length() == 1 && line[0] == '\n') {
				client.println(prepareHtmlPage());
				break;
			}
		}
	}
	delay(1);	// データを受信する時間をWebブラウザに与える

	// 接続を閉じる:
	client.stop();
	Serial.println("[Client disonnected]");
}
}
スケッチの中で使用されているWiFiServerWiFiClientクラスのメソッドを順に紹介していきます。

最初にサーバーオブジェクトを作成し、

WiFiServer()

説明

指定されたポートで着信接続をアクセス待機するサーバーを作成します。

構文

WiFiServer(const IPAddress& addr,uint16_t port);
WiFiServer(uint16_t port);

パラメータ

  • addr使用環境のローカルIPアドレス
  • port アクセス待機するポート(整数)

使用例

	WiFiServer server(80);
次に、void setup() {}の中でサーバーを起動。

Server.begin()

説明

着信接続のアクセス待機を開始するようサーバーに指示します。

構文

void begin();
void begin(uint16_t port);

パラメータ

  • port アクセス待機指示したポート(整数)

使用例

	server.begin();
途中、サーバーからのレスポンス用にステータスライン、レスポンスヘッダ、HTMLドキュメントを設定した箇所がありますが、ここではスルーして進めます。

以降は、void loop() {}の中で設定されているメソッド。
クライアントオブジェクトを作成

WiFiClient()

説明

client.connect()で定義されている指定のインターネットIPアドレスおよびポートに接続できるクライアントを作成します。

構文

WiFiClient();

パラメータ

なし

使用例

	WiFiClient client;
サーバーに接続されているクライアントを取得。接続されているクライアントが無ければfalseになります。

Server.available()

説明

サーバーに接続され、読み取り可能なデータを持つクライアントを取得します。返されたクライアントオブジェクトが範囲外になっても、接続は維持されます;client.stop()を呼び出して閉じることができます。

available()は、Streamユーティリティクラスを継承します。

構文

Server available(uint8_t* status = NULL);

パラメータ

なし

戻り値

Clientオブジェクト;クライアントに読み込み可能なデータがない場合、このオブジェクトはif文でfalseと評価されます。

使用例

	WiFiClient client = server.available();
クライアントが接続されていて、データが読み込み中であるかの検証。
クライアントが接続と判定されている期間ループ処理されます。

WiFiClient.connected()

説明

クライアントが接続されているかどうかを確認します。接続が閉じられていても、まだ読み込まれていないデータがある場合、クライアントは接続されていると見なされます。

構文

WiFiClient.connected();

パラメータ

なし

戻り値

クライアントが接続されている場合はtrue、接続されていない場合はfalseを返します。

使用例

	while (client.connected()) {

	}
クライアントに送信されているデータ量を取得

WiFiClient.available()

説明

読み取り可能なバイト数(つまり、接続されているサーバによってクライアントに書き込まれたデータの量)を返します。

構文

WiFiClient.available();

パラメータ

なし

戻り値

使用可能なバイト数。

使用例

		if (client.available()) {

		}
指定文字までの文字列を取得する。
スケッチでは、改行文字を指定する事で1行単位での読み込みを行なっている。

WiFiClient.readStringUntil()

説明

クライアントから文字をString(に読み込みます。terminator文字が検出された場合、またはタイムアウトになった場合は終了します。(setTimeout()を参照)

構文

WiFiClient.readStringUntil(terminator);

パラメータ

  • terminator 検索する文字(char)

戻り値

読み込んだ先頭からterminator文字までの文字列全体

使用例

			String line = client.readStringUntil('\r');
クライアントに対してprintln()が実行されると思っていたのですが、クライアントが接続しているサーバーに対して行われるようです。で、結果としてサーバーへアクセスしているクライアントに反映される仕組みですね。

WiFiClient.println()

説明

クライアントが接続されているサーバーに、キャリッジ・リターンと改行を付けてデータを出力します。数値の場合は、数字を連続したASCII文字列として出力します(たとえば、数字の'123'だと '1','2','3'の三文字として送信されます)。

構文

client.println();
client.println(data);
client.println(data, BASE);

パラメータ

  • data 出力するデータ(char、byte、int、long、またはstring)
  • BASE 数値を出力する際の基数です。10進数の場合はDEC(base 10)、8進数の場合はOCT(base 8)、16進数の場合はHEX(base 16)です。

戻り値

byte:書き込まれたバイト数を返しますが、その数の読み取りはオプションです。

使用例

				client.println(prepareHtmlPage());
クライアントとの接続を閉じる。

WiFiClient.stop()

説明

サーバーから切断する

構文

WiFiClient.stop();

パラメータ

なし

使用例

	while (client.connected()) {

	}
ソースコードを眺めている限り、なんだか随分まわりくどい流れな気もしますが、とりあえずArduino IDEでESP-WROOM-02へ書き込んで実行してみましょう。

シリアルモニタは以下のような表示。
※ESP-WROOM-02を再起動しないと表示されないかも?
Connecting...... connected
Web server started, open XXX.XXX.XXX.XXX in a web browser
で、表示されているIPアドレス(XXX.XXX.XXX.XXXの箇所)をブラウザで開くと、クライアントの接続が確立されて、シリアルモニタが以下のように更新。
[Client connected]
GET / HTTP/1.1
Host: XXX.XXX.XXX.XXX
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X XX_XX_X) AppleWebKit/XXX.X.XX (KHTML, like Gecko) Version/XX.X.X Safari/XXX.X.XX
Accept-Language: ja-jp
Accept-Encoding: gzip, deflate
Connection: keep-alive
[Client disonnected]

[Client connected]
ブラウザには、サーバーに設定されたドキュメントの表示が行われます。

Webサーバーと直接関係する内容ではありませんが、ここで表示されているAnalog inputの値は、ESP-WROOM-02の唯一のアナログ入力ピンである16:TOUTの値を示しています。analogRead(A0)で得られる数値は、0.0~1.0Vの電圧を0~1023の10bit値で表したものとなります。TOUTには何も接続していませんが、ライン上には電流が流れているので、0.1V前後を指す値が表示されています。
このページは5秒ごとに更新されます。(Chromeだと更新されません)
更新が発生すると、シリアルモニタでも内容が以下の様に変更され、ブラウザの表示値(Analog inputの値)も変化します。
GET / HTTP/1.1
Host: XXX.XXX.XXX.XXX
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X XX_XX_X) AppleWebKit/XXX.X.XX (KHTML, like Gecko) Version/XX.X.X Safari/XXX.X.XX
Referer: http://XXX.XXX.XXX.XXX/
Cache-Control: max-age=0
Accept-Language: ja-jp
[Client disonnected]

[Client connected]
以降、ページを開いたままにしておくと5秒毎にシリアルモニタの情報とページの値が更新され続けます。

以上で、Webサーバーの構築は完了。

次回は、ESP8266WebServer.hについて調査予定。

0 件のコメント:

コメントを投稿