2019年9月27日金曜日

ArduinoとESP-WROOM-02でWiFi Webサーバー

前回("ESP-WROOM-02のATモードでWeb Server構築")の続き。

ATコマンドで立ち上げたWebサーバーは、フラッシュメモリに記録されないため、電源を落とすと再びATコマンドを入力しないと起動しません。
ここでは、その一連の入力作業をArduinoに担当してもらう事にします。

一番の問題は、Arduinoでプログラムを組むのが久々すぎて完全に忘れている事。
思い出しつつ書いているのもあり、関数化などはせず、あくまでベタに書き進めます。

また、送信についてはloop内を除き、Serialは"println"、ソフトウェアシリアルは"write"で統一してあるので、その辺りも踏まえてコードを見ると比較的理解しやすいのでは?と、勝手に思っています。

Webサーバー起動のために入力が必要なATコマンドのおさらい。
  • AT+CIPMUX=1
  • AT+CIPSERVERMAXCONN=2
  • AT+CIPSERVER=1,80
  • AT+CIPSEND=0,23
  • <H1>Hello Arduino!</H1>
  • AT+CIPCLOSE=0
上記、6つのコマンドと数値、文字列をArduinoから送信すれば前回同様に動作するはず。。。 ってコトで、コードを書いてみます。 ただし、
  • AT+CIPSEND=0,23
  • <H1>Hello Arduino!</H1>
  • AT+CIPCLOSE=0
の3つについては、ブラウザからのアクセスが発生して以降でないと実行出来ないので一旦除外。
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); 	// RX, TX

void setup() {
	// ハードウェアシリアルポートのデータレートを設定する
	Serial.begin(9600);

	// ソフトウェアシリアルポートのデータレートを設定する
	mySerial.begin(9600);

	mySerial.write("AT+CIPMUX=1\r\n");				// サーバーを複数接続に設定
	mySerial.write("AT+CIPSERVERMAXCONN=2\r\n");	// 複数接続の最大数を設定
	mySerial.write("AT+CIPSERVER=1,80\r\n");			// サーバを起動
}

void loop() {
	if (mySerial.available()) {
		Serial.write(mySerial.read());
	}
}
何も考えずに、ざっくり組み込むとこんな感じになって、以下のような表示となり、Webサーバーとしては動作しません。
AT+CIPMUX=1
AT+CIPSERVERMAXCONN=2

busy p...
AT+CIPSERVER=1,80

busy p...

OK
動作しない理由は、ATコマンドの実行中に次のコマンドが送信されて、実行されないまま終了しているからです。それを説明しているのが"busy p..."の箇所。

busy p...処理中。 システムは前のコマンドを処理していますが、新しく入力を受け付けることができません。
なので、"delay()"で適当な待機時間を設定すれば動くのですが、コマンドが正常に実行されたか確認するために戻り値を取得する方法を検討してみたいと思います。
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); 	// RX, TX

void setup() {
	// ハードウェアシリアルポートのデータレートを設定する
	Serial.begin(9600);

	// ソフトウェアシリアルポートのデータレートを設定する
	mySerial.begin(9600);

	mySerial.write("AT+CIPMUX=1\r\n");				// サーバーを複数接続に設定
	String ret = mySerial.readString();
	ret.replace("\r\n\r\n", "\r\n");
	Serial.println(ret);
	mySerial.write("AT+CIPSERVERMAXCONN=2\r\n");	// 複数接続の最大数を設定
	ret = mySerial.readString();
	ret.replace("\r\n\r\n", "\r\n");
	Serial.println(ret);
	mySerial.write("AT+CIPSERVER=1,80\r\n");			// サーバを起動
	ret = mySerial.readString();
	ret.replace("\r\n\r\n", "\r\n");
	Serial.println(ret);
}

void loop() {
	if (mySerial.available()) {
		Serial.write(mySerial.read());
	}
}
実行すると、シリアルモニタに以下の表示。
スケッチで空行を省いて表示する様にしています。
AT+CIPMUX=1
OK

AT+CIPSERVERMAXCONN=2
OK

AT+CIPSERVER=1,80
OK
ここでは全部"OK"になるように電源投入時の状態で実行しているので、想定通りの表示。既にサーバーを起動している状態で実行すると、
AT+CIPMUX=1
OK

AT+CIPSERVERMAXCONN=2
ERROR

AT+CIPSERVER=1,80
no change
OK
の様に一部でエラーが返ってきますが、既定値があるためのエラーで問題はありません。気になるようであればESP-WROOM-02をリセットするとエラーが消えます。 話を戻して、ブラウザに"ESP-WROOM-02のIPアドレス:80"を指定して開くと、シリアルモニタにさらに以下の様な表示がされて、サーバーとして機能している事も確認出来るかと思います。
0,CONNECT
1,CONNECT

+IPD,0,XXX:GET / HTTP/1.1
Host: XXX.XXX.XXX.XXX
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_XX_X) AppleWebKit/XXX.XX (KHTML, like Gecko) Chrome/XX.X.XXXX.XXX Safari/XXX.XX
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: ja,en;q=0.9,und;q=0.8

0,CLOSED
ブラウザからのアクセスを認識出来たので、
  • AT+CIPSEND=0,23
  • <H1>Hello Arduino!</H1>
  • AT+CIPCLOSE=0
の送信を組み込んでみます。 ついでにWebサーバーのアドレス表示するように修正。
#include <SoftwareSerial.h>

SoftwareSerial mySerial(10, 11); 	// RX, TX

void setup() {
	// ハードウェアシリアルポートのデータレートを設定する
	Serial.begin(9600);

	// ソフトウェアシリアルポートのデータレートを設定する
	mySerial.begin(9600);

	mySerial.write("AT+CIPMUX=1\r\n");				// サーバーを複数接続に設定
	String ret = mySerial.readString();
	ret.replace("\r\n\r\n", "\r\n");
	Serial.println(ret);
	mySerial.write("AT+CIPSERVERMAXCONN=2\r\n");	// 複数接続の最大数を設定
	ret = mySerial.readString();
	ret.replace("\r\n\r\n", "\r\n");
	Serial.println(ret);
	mySerial.write("AT+CIPSERVER=1,80\r\n");			// サーバを起動
	ret = mySerial.readString();
	ret.replace("\r\n\r\n", "\r\n");
	Serial.println(ret);

	// ESP-WROOM-02のIPアドレス取得
	mySerial.write("AT+CIFSR\r\n");
	ret = mySerial.readString();
	int first = ret.indexOf('"')+1;
	int last  = ret.indexOf('"', first+1);
	String ip_add = ret.substring(first, last);
	Serial.println("http://"+ip_add+":80");
}

void loop() {
	if (mySerial.available()) {
		String ret = mySerial.readString();
		if ( ret.indexOf("IPD") > 0 ) {
			mySerial.write("AT+CIPSEND=0,20\r\n");		// 指定された長さのデータを送信
			ret = mySerial.readString();
			ret.replace("\r\n\r\n", "\r\n");
			Serial.println(ret);
			mySerial.write("<H1>Hello WiFi!</H1>\r\n");	// HTML書式のデータを指定
			ret = mySerial.readString();
			ret.replace("\r\n\r\n", "\r\n");
			Serial.println(ret);
			mySerial.write("AT+CIPCLOSE=0\r\n");			// 接続を閉じる
			ret = mySerial.readString();
			ret.replace("\r\n\r\n", "\r\n");
			Serial.println(ret);
		}
	}
}
実行結果。
一連の動作結果を、"ESP-WROOM-02のATモードでWeb Server構築"と比較してみると正常に稼働しているのか確認出来ます。
AT+CIPMUX=1
OK

AT+CIPSERVERMAXCONN=2
OK

AT+CIPSERVER=1,80
OK

http://XXX.XXX.XXX.XXX:80
AT+CIPSEND=0,23
OK
> 

busy s...
Recv 23 bytes
SEND OK

AT+CIPCLOSE=0
0,CLOSED
OK
+IPD,1,XXX:GET /favicon.ico HTTP/1.1
Host: XXX.XXX.XXX.XXX
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_XX_X) AppleWebKit/XXX.XX (KHTML, like Gecko) Chrome/XX.X.XXXX.XX Safari/XXX.XX
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://XXX.XXX.XXX.XXX/
Accept-Encoding: gzip, deflate
Accept-Language: ja,en;q=0.9,und;q=0.8
一部で見た事あるメッセージ"busy s..."の表示があります。

busy s...送信中。 システムは現在データを送信していますが、新しい入力を受け入れることができません。
"busy s..."は、"busy p..."と異なり新規コマンドの即時実行出来ないだけで処理自体は実行されているので、指定通りの動作が行われます。 ブラウザには前回同様の表示。
ここから先は、重複箇所を関数にしてスケッチを簡略化したり、"link ID"に対応したり、データ長を自動取得したり、エラー対策したり、ESP-WROOM-02のリセット、Arduinoのリセットなど諸々改修出来る箇所があります。
たちまち、やんないですけど。。。

次は、もう少し動的な動作も試して見る予定。

0 件のコメント:

コメントを投稿