ATコマンドでTCP接続をしてみる
それでは、ESP-WROOM-02U を使用して TCP 通信を行ってみましょう。まずは ATコマンドを手打ちしてWebサーバに接続し、htmlファイルを取得してみます。
準備
テスト用htmlファイルの準備
接続先のWebサーバとして、PC 上に XAMPP をインストール&起動し、Wifi接続するネットワーク上のホストからアクセス可能なようにファイアウォールを適切に設定しておきます。また、取得するファイルとして、ドキュメントルート直下に以下のファイル test.html を配置します。
<!DOCTYPE html>
<html>
<head>
<title>Web Test</title>
</head>
<body>
<h1>Web Test Page</h1>
</body>
</html>
製作
スケッチ
Arduino IDEで以下のスケッチをコンパイル&実行して下さい。内容は先の通信速度設定のプログラムから、シリアルモニタでATコマンドを実行できるようにした部分だけを抜き出したものです。
#include <SoftwareSerial.h>
SoftwareSerial wifiSerial(2, 3); // RxD=2, TxD=3
void setup() {
Serial.begin(9600);
wifiSerial.begin(9600);
}
void loop() {
if (Serial.available()) {
wifiSerial.write(Serial.read());
}
if (wifiSerial.available()) {
Serial.write(wifiSerial.read());
}
}
実行
それでは、動作テストの時と同様、Arduinoのシリアルモニタを使って以下のコマンドを順番に実行してみましょう。
コマンド:AT+CWMODE=1
AT+CWMODE コマンドで、ステーションモードに切り替えます。詳しい説明は前記事をご覧下さい。
コマンド:AT+CWJAP=”ssid“,”password“
AT+CWJAP コマンドは、アクセスポイントに接続します。詳しい説明は前記事をご覧下さい。
コマンド:AT+CIPSTART=”TCP”,”host_address“,80
AT+CIPSTART コマンドは、指定のホストに接続します。コマンドの書式は、
AT+CIPSTART="protocol","host_address",port
です。指定する値は以下の3つです。
項目 | 意味 | 値の例 |
---|---|---|
protocol | 接続プロトコルを表す文字列 | “TCP” |
host_address | 接続先のIPアドレスまたはドメインを表す文字列 | “192.168.0.1” |
port | 接続先のポート番号を表す数値 | 80 |
接続すると、
CONNECT
OK
とメッセージが返ってきます。

自前で実験用サーバが用意できない場合は、本サイトのファイルをご利用下さい。
接続コマンドは
AT+CIPSTART="TCP","workshop.aaa-plaza.net",80
となります。
コマンド:AT+CIPMODE
AT+CIPMODE は、ATコマンドモードまたはパススルーモードを設定します。パラメータはモードを表す数値です。
0 を指定するとコマンドモードになります。ESP-WROOM-02U にシリアル送信したデータ(文字列)は、コマンドとして解釈されます。
1 を指定するとパススルー(トランスペアレント)モードになります。このモードでは、ESP-WROOM-02U にシリアル転送されたデータは、そのままWifiでネットワークに送出されます。
この実験ではパススルーモードに変更するので、コマンドは
AT+CIPMODE=1
となります。モード変更に成功すると
OK
というメッセージが返ってきます。
コマンド:AT+CIPSEND
AT+CIPSEND コマンドは、データをネットワークに送信するコマンドです。
コマンドモード(CIPMODE=0)の場合はコマンドのパラメータとして送信データを記述しますが、
パススルーモード(CIPMODE=1)の場合はパラメータなしでこのコマンドを実行した後、
OK
>
とメッセージが返され、これ以降の入力がWifiでネットワークに送出されるようになります。
リクエスト文字列:GET /test.html HTTP/1.0
これは ESP-WROOM-02U でコマンドとして解釈される文字列ではなく、Wifiでネットワークに送出され、Webサーバに届く HTTP のリクエストです。
GET /test.html HTTP/1.0
2行目に空行があることに注意して下さい。『GET~』の行を入力した後、もう一度シリアルモニタの送信文字列入力欄で Enter を空打ちし、CR+LF を送信します。ここまでのATコマンド入力と異なり、『GET~』の部分はエコーバック(受信欄に表示)されません。
成功すると、以下のようなWebサーバからのレスポンスが表示されます。
HTTP/1.1 200 OK
Date: Tue, 03 Oct 2023 14:57:45 GMT
Server: Apache/2.4.27 (Win32) OpenSSL/1.0.2l PHP/7.1.9
Last-Modified: Mon, 02 Oct 2023 08:06:30 GMT
ETag: "75-606b74079bbe2"
Accept-Ranges: bytes
Content-Length: 117
Connection: close
Content-Type: text/html
<!DOCTYPE html>
<html>
<head>
<title>Web Test</title>
</head>
<body>
<h1>Web Test Page</h1>
</body>
</html>

本サイトのサーバで実験する場合は、リクエストヘッダに Host: フィールドが必須ですので、送信する文字列は以下のようになります。
GET /test.html HTTP/1.0
Host: workshop.aaa-plaza.net
3行目が空行であることに注意して下さい。1行目・2行目を入力した後、もう一度シリアルモニタの送信文字列入力欄が空のまま Enter キーを空打ちし、CR+LFを送信します。
+++(パススルーモードの終了)
パススルーモードでは(当然ながら)コマンドを受け付けません。パススルーモードを終了するには、改行コードを『なし』に設定した状態で『+++』(半角のプラスを3つ)を送信して1秒待つ、という特殊な手順が必要です。

コマンド:AT+CIPCLOSE
AT+CIPCLOSE コマンドは、通信を終了します。コマンド入力の前に、『改行なし』に変更したのを『CRおよびLF』に戻すのを忘れないようにして下さい。

成功すると
CLOSED
OK
というメッセージが返ってきます。
これでATコマンド手打ちによるTCP接続の実験は終了です。
プログラムからTCP接続する(クライアントとして)
では今度は、プログラムから自動的に通信してみましょう。最初の例として、ATコマンドで試したのと同様にWebサーバに対してクライアントとして接続するプログラムを作成します
準備
ライブラリのインストール
Arduino上のプログラムから ESP-WROOM-02 を Wifiモジュールとして扱うには、もちろんSofwareSerial.print(“AT+CWMODE=1”); などとATコマンドを送信するプログラムを作成しても動くことは動くのですが、さすがにプログラミングの手間が大きくなります。そこで、簡単にESP-WROOM-02(というかESP8266)を利用できるライブラリをインストールしてしまいましょう。
ダウンロード
まず、こちらのサイトにアクセスして下さい。
ライブラリファイル『ITEADLIB_Arduino_WeeESP8266-master.zip』をダウンロードします。

インストール
Arduino IDEを起動し、メニューの『スケッチ』→『ライブラリをインクルード』→『ZIP型式のライブラリをインストール』を順にクリックします。
ファイル選択画面が表示されたら、先ほどダウンロードした『ITEADLIB_Arduino_WeeESP8266-master.zip』を選択します。

ソースを修正
当サイトのWifi関係の実験では、Arduino と ESP-WROOM-02 との通信に SoftwareSerial を使用する予定です。しかしインストールしたライブラリは、デフォルトでは SoftwareSerial に対応していません。対応させるためには、少々のソースの修正が必要です。
とはいっても、修正は簡単です。ライブラリがインストールされたフォルダ(Windowsの場合、デフォルトでは ドキュメント\Arduino\libraries\ITEADLIB_Arduino_WeeESP8266-master\)の中にある ESP8266.h をテキストエディタで開き、27行目の行頭にある『//』を削除して上書き保存するだけです。コンパイル等は不要です。
修正前

↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
修正後

以上で、Arduino IDEでWifi(ESP8266)用のライブラリを使用できるようになります。
スケッチ
今回のスケッチは以下の通りです。
#include "ESP8266.h"
#include <SoftwareSerial.h>
// 以下は各自の環境に合わせて下さい
#define SSID ”HOMENETWORK"
#define PASSWORD "wifipassword"
#define HOST_ADDR "192.168.0.15"
#define HOST_PORT 80
#define HOST_FILE "test.html"
SoftwareSerial wifiSerial(2, 3); // RxD=2, TxD=3
ESP8266 wifi(wifiSerial);
void setup(void)
{
Serial.begin(9600);
wifiSerial.begin(9600);
// wifi restart
Serial.print("wifi restart.");
while(!wifi.restart()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
// kick (check alive)
Serial.print("kicking.");
while(!wifi.kick()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
// set station mode
Serial.print("set station mode.");
while(!wifi.setOprToStation()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
// join to AP(SSID,PASSWORD)
Serial.print("join to AP.");
while(!wifi.joinAP(SSID, PASSWORD)){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
// set single mode
Serial.print("set single mode.");
while(!wifi.disableMUX()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
// TCPサーバへ接続
Serial.print("connect to TCP server.");
while(!wifi.createTCP(HOST_ADDR, HOST_PORT)){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
Serial.println();
// Webサーバへリクエストを送信
char sendBuffer[128];
sprintf(sendBuffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",HOST_FILE,HOST_ADDR);
wifi.send(sendBuffer, strlen(sendBuffer));
// Webサーバよりレスポンスを受信
char recvBuffer[512];
int len;
if((len=wifi.recv(recvBuffer,sizeof(recvBuffer)-1,10000))>0){
recvBuffer[len]='\0';
Serial.println(recvBuffer);
}
// TCP接続を解除(HTTPなのでサーバ側から既に切られているはずだけど念のため)
Serial.print("TCP disconnect.");
wifi.releaseTCP();
Serial.println("ok");
// 無線LAN切断
Serial.print("Leave from AP.");
Serial.println("ok");
wifi.leaveAP();
}
void loop(void)
{
}
長いですが、実は78行目以外の Serial.print() や Serial.println() はプログラム自体の動作確認用なので、機能には関係ありません。ESP8266 関係の関数は実行に少々時間がかかるものが多く、実験に用いた環境だとAPに接続完了するまでに数十秒かかることがあるのですが、どこまで進んだか判らないままずっと待たされるのが嫌な性分なので…。不要なら省略して下さい。
コードの解説
include
#include "ESP8266.h"
#include <SoftwareSerial.h>
ESP8266.h には、ESP-WROOM-02U をはじめとする ESP8266搭載のWifiモジュールを利用するための関数群 が定義されています。先にインストールした ITEADLIB_Arduino_WeeESP8266-master に含まれています。
SoftwareSerial は、Arduino と ESP8266(ESP-WROOM-02U)が通信するために必要です。
定数定義
#define SSID ”HOMENETWORK"
#define PASSWORD "wifipassword"
#define HOST_ADDR "192.168.0.15"
#define HOST_PORT 80
#define HOST_FILE "test.html"
アクセスポイントおよびWebサーバについての情報です。お使いの環境に合わせて書き換えて下さい。
定数名 | 意味 | 値の例 |
---|---|---|
SSID | 接続するアクセスポイントのSSID | “HOMENETWORK” |
PASSWORD | 接続するアクセスポイントのパスワード | “wifipassword” |
HOST_ADDR | 接続するWebサーバのIPアドレスまたはサーバ名 | “192.168.0.15” または “workshop.aaa-plaza.net” |
HOST_PORT | Webサーバのポート番号 | 80 |
HOST_FILE | 取得するファイルのファイル名 | “test.html” |
ESP8266オブジェクトの生成
SoftwareSerial wifiSerial(2, 3); // RxD=2, TxD=3
ESP8266 wifi(wifiSerial);
ESP8266 を制御するためには、ESP8266クラス のオブジェクトを使用します。ESP8266クラスは内部的に SoftwareSerial を使用するため、先に SoftwareSerialクラスのオブジェクト を生成し、次にwifiSerialを引数としてESP8266クラスのオブジェクト を生成する、という手順になります。
SoftwareSerialクラスのオブジェクトの生成では、引数として『RxDとして利用する端子の番号』と『TxDとして利用する端子の番号』を与えます。この例ではRxD=2、TxD=3として、SoftwareSerialクラスのオブジェクト wifiSerial を生成しています。
次に、ESP8266クラスのオブジェクトの生成では、引数としてArduino と ESP8266 の通信に使用する SoftwareSerial のクラスを与えます。この例では wifiSerial を与えて ESP8266クラスのオブジェクト wifi を生成しています。
シリアル通信速度の設定
void setup(void)
{
Serial.begin(9600);
wifiSerial.begin(9600);
setup() 関数内の最初で、PC ~ Arduino 間および Arduino ~ ESP-WROOM-02U 間でのシリアル通信速度を設定しています。
Serial.begin() が PC ~ Arduino 間、
wifiSerial.begin() が Arduino ~ ESP-WROOM-02 間
です。この例ではともに 9600bps です。
ESP8266 の再起動
ここからが ESP8266 での通信のためのスクリプトです。
Serial.print("wifi restart.");
while(!wifi.restart()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
まず、ESP8266 を再起動します。再起動には ESP8266::restart() 関数を使用します。
書式
bool ESP8266::resart(void)
引数
なし
返却値
値 | 意味 |
---|---|
true | 再起動に成功 |
false | 再起動に失敗 |
解説
このメソッドは ESP8266 を再起動します。処理に3秒程度かかります。
※電源起動直後でも『再起動』です。このrestart()の他に『初回起動用』の関数があるわけではありません。
内部的には、『AT+RST』コマンドを送信して、一定時間内に『OK』を含むリプライが返ってくるかを確認しているようです。
この例では、falseが返って来た場合は 1000 ms=1秒待ってからリトライするようにしています。また Serial.print() や Serial.println() で動作確認メッセージを表示するようにしていますが、これらが不要の場合は、最小限
wifi.restart();
だけでも動きます。
これ以降、『確認メッセージ表示』および『失敗したら1秒待ってリトライ』はすべて同じなので、ESP8266.h で定義されているメソッドのみ解説します。
ESP8266の動作確認
// kick (check alive)
Serial.print("kicking.");
while(!wifi.kick()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
ESP8266 が動作しているかを確認するには、ESP8266::kick() 関数を使用します。
書式
bool ESP8266::kick(void)
引数
なし
返却値
値 | 意味 |
---|---|
true | 動作している |
false | 動作していない |
解説
内部的には、『AT』コマンドを送信して、一定時間内に『OK』を含むリプライが返ってくるかを確認しているようです。
今回のプログラムでは、kick()関数がtrueを返すまでループします。
ステーションモードに設定
// set station mode
Serial.print("set station mode.");
while(!wifi.setOprToStation()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
今回の実験では、ESP8266 をステーションモード(ESP8266 を既存のアクセスポイントに接続するクライアント側として使用するモード)に設定します。
この設定には ESP8266::setOprToStation() 関数を使用します。
書式
bool ESP8266::setOprToStation(void)
引数
なし
返却値
値 | 意味 |
---|---|
true | ステーションモードへの切り替えに成功 |
false | ステーションモードへの切り替えに失敗 |
解説
この関数は、内部的には『AT+CWMODE=1』を送っています。
今回のプログラムでは、setOprToStation()関数がtrueを返すまでループします。
アクセスポイントへ接続
// join to AP(SSID,PASSWORD)
Serial.print("join to AP.");
while(!wifi.joinAP(SSID, PASSWORD)){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
ESP8266をアクセスポイントに接続します。
接続には ESP8266::joinAP() 関数を使用します。
書式
bool ESP8266::joinAP(String ssid, String password)
引数
名前 | 型 | 意味 |
---|---|---|
ssid | String | 接続するアクセスポイントのSSID |
password | String | 接続するアクセスポイントのパスワード |
返却値
値 | 意味 |
---|---|
true | 接続に成功 |
false | 接続に失敗 |
解説
この処理には、数秒~数十秒の時間がかかります。
今回のプログラムでは、joinAP()関数がtrueを返すまでループします。
シングル(単一接続)モードに設定
ここから先は TCP/UDP に関する設定です。
// set single mode
Serial.print("set single mode.");
while(!wifi.disableMUX()){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
まず、今回の実験では ESP8266 を TCPクライアントとして動作させるので、TCP/UDP において一度に単一の相手とだけ接続する『シングルモード』に設定をします。
この設定には ESP8266::disableMUX() 関数を使用します。
書式
bool ESP8266::disableMUX(void)
引数
なし
返却値
値 | 意味 |
---|---|
ture | シングルモードへの切り替えに成功 |
false | シングルモードへの切り替えに失敗 |
今回のプログラムでは、disableMUX()関数がtrueを返すまでループします。
TCPコネクションの作成(クライアントとして)
// TCPサーバへ接続
Serial.print("connect to TCP server.");
while(!wifi.createTCP(HOST_ADDR, HOST_PORT)){
Serial.print(".");
delay(1000);
}
Serial.println("ok");
Serial.println();
指定されたサーバに対して、ESP8266 を TCPクライアントとしてシングルモードでコネクションを作成(接続)します。
接続には ESP8266::createTCP() 関数を使用します。
書式
bool ESP8266::createTCP(String addr, uint32_t port)
引数
名前 | 型 | 意味 |
---|---|---|
addr | String | 接続先サーバのIPアドレス、またはFQDN |
port | uint32_t | 接続先のポート番号 |
返却値
型 | 意味 |
---|---|
true | TCP接続に成功 |
false | TCP接続に失敗 |
解説
接続先のアドレス(またはホスト名)とポートを指定してTCP接続します。
今回のプログラムでは、引数として与えるアドレスやポート番号は、プログラム冒頭部でそれぞれ #define HOST_ADDR および #define HOST_PORT で定数として定義しています。
Webサーバに接続するのでportは80としていますが、実験環境など異なるポート番号でWebサーバを運用している場合にはプログラム冒頭部の #define HOST_PORT の値を書き換えて下さい。
サーバにデータを送信する
TCP接続に成功したら、Webサーバに対してHTTPリクエストメッセージを送信します。
// Webサーバへリクエストを送信
char sendBuffer[128];
sprintf(sendBuffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",HOST_FILE,HOST_ADDR);
wifi.send(sendBuffer, strlen(sendBuffer));
送信するデータ
今回の実験では、Webサーバに対してHTTPリクエストメッセージ(GETメソッド)を送信します。具体的には以下のようなものです。
GET サーバ上のファイル名 HTTP/1.0
Host: ホスト名
1行目の『GET~』は、『サーバ上の、指定したファイルの内容を送れ』というものです。HTTPリクエストでは、最初に『GET~』のように、Webサーバに対して『○○してくれ』という内容の行が来ます。これを『リクエスト行』といいます。リクエスト行は先頭に必ず1行だけ存在します。
2行目以降には、0行以上の『ヘッダ』が続きます。これはリクエストにあたって付加的な情報をサーバに伝えるためのものです。今回の実験では、『Host~』という行を追加しています。これはサーバ側が同じIPアドレスで複数のホストを運用していた場合に、どのホストに対するリクエストかを区別するためのものです。
ヘッダの後には空行が必要です。Webサーバは、クライアントから改行文字だけの行が送られてくるまで、まだヘッダの続きがあるものとして受信待ちをし、レスポンスを返してくれません。上記送信文字列例でも3行目に改行文字だけの行があることに注意して下さい。
※詳しくは、HTTPについて解説されている書籍やサイトを参照して下さい
サーバ上のファイル名は、プログラム冒頭の #define HOST_FILE で定義しています。
この送信文字列を組み立てているのが、
char sendBuffer[128];
sprintf(sendBuffer, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n",HOST_FILE,HOST_ADDR);
の部分です。char型配列変数sendBuffer内に送信文字列を組み立てています。最後の”\r\n\r\n”で空行を追加しています(2行目の行末”\r\n”+3行目の空行”\r\n\r\n”)。
送信コマンド
メッセージの送信には ESP8266::send() 関数を使用します。
書式
bool ESP8266::send(const uint8_t *buffer, uint32_t len)
引数
名前 | 型 | 意味 |
---|---|---|
buffer | const uint8_t | 送信するデータバッファ(uint8_tのデータ列)へのポインタ |
len | uint32_t | 送信するデータの長さ |
返却値
値 | 意味 |
---|---|
true | 送信に成功 |
false | 送信に失敗 |
このプログラムでは、
wifi.send(sendBuffer, strlen(sendBuffer));
としてsendBufferのデータを送信しています。
サーバからのデータを受信する
クライアントからサーバへHTTPリクエストメッセージを送信すると、サーバはクライアントにHTTPレスポンスメッセージを返信します。HTTPレスポンスメッセージもリクエストメッセージと同様の構造があるのですが、今回は受信したメッセージの分析はしないので説明は省略します。
サーバからのメッセージを受信するには、ESP8266::recv() 関数を使用します。
書式
uint32_t ESP8266::recv(uint8_t *buffer, uint32_t buffer_size [ , uint32_t timeout = 1000])
引数
名前 | 型 | 意味 |
---|---|---|
buffer | uint8_t* | 受信バッファへのポインタ |
size | uint32_t | 受信バッファのサイズ |
timeout | uint32_t | タイムアウトまでの時間をmsで指定。省略すると 1000 ms となる。 |
返却値
型 | 意味 |
---|---|
uint32_t | 受信したデータの長さ(バイト数) |
このプログラムでは、
char recvBuffer[512];
int len;
if((len=wifi.recv(recvBuffer,sizeof(recvBuffer)-1,10000))>0){
recvBuffer[len]='\0';
Serial.println(recvBuffer);
}
としています。まず512バイトのchar型配列 recvBuffer を宣言して受信のための領域を確保しています。
recv() メソッドはメッセージを受信するか、またはタイムアウトするまで待ちますが、タイムアウトだった場合は受信したメッセージのバイト数が0になるのでif文で分岐し、受信したメッセージがあった場合のみその処理を行っています。
recv() メソッドで受信したデータが文字列だったとしても、文字列終端を表す ‘\0’(ヌル文字)が付かないため、
recvBuffer[len]='\0';
として終端に’\0’を追加しています。
このプログラムでは、受信したHTTPレスポンスをそのまま(ヘッダもデータ本体もすべて) Serial.println() でPCに転送しています。
TCPコネクションの解放
通信が終了したら、TCPコネクションを解放(切断)します。
// TCP接続を解除(HTTPなのでサーバ側から既に切られているはずだけど念のため)
Serial.print("TCP disconnect.");
wifi.releaseTCP();
Serial.println("ok");
※HTTPの場合、リクエスト/レスポンスでデータが一往復したらサーバ側から切断されてしまうので、必ずしもこの処理は必要ではないかもしれません。
TCPコネクションを解放するには、 ESP8266::releaseTCP() 関数を使用します。
書式
bool ESP8266::releaseTCP(void)
引数
なし
返却値
値 | 意味 |
---|---|
true | 解放に成功 |
false | 解放に失敗 |
アクセスポイントから切断
最後に、アクセスポイントから切断します。
// 無線LAN切断
Serial.print("Leave from AP.");
Serial.println("ok");
wifi.leaveAP();
アクセスポイントからの切断には、ESP8266::leaveAP() 関数を使用します。
書式
bool ESP8266::leaveAP(void)
引数
なし
返却値
値 | 意味 |
---|---|
true | 切断に成功 |
false | 切断に失敗 |
本プログラムは setup() の中の処理だけで完結しています。loop() 内は空です。
実行
Arduino と PC をUSBケーブルで接続し、Arduino IDE でシリアルモニタを開いた状態でスケッチを実行sしてみましょう。

このような結果が得られれば成功です(レスポンスヘッダの内容は環境によって異なります)。
次の記事では Arduino+ESP8266 をTCPサーバとして動作させます。
まとめ
- ATコマンドでTCP接続できる
- ESP8266.h のようなライブラリを利用すると比較的巻単位WiFi接続・TCP接続ができる
コメント