2015.12.25
- 人×技術
ESP8266を使ってArduinoからネットワーク接続してみる
こんにちは、イシイです。
Arduinoからネットワーク接続を行おうとする場合、イーサネットケーブル有りであればイーサネットシールド、3Gであれば3Gシールドや3GIMなどがありますが、ケーブルが煩わしかったり値段がお高かったりします。WiFi シールドであればその辺りは比較的改善できそうではありますが、今回はもっと格安で小さくてネットワーク接続できるWi-Fiモジュール「ESP8266」が搭載されているESP-WROOM-02を使ってみました。
ESP8266
ESP8266は、技適も通っているWi-Fiモジュールなので、日本での使用も特に問題ありません。また、ESP8266自体にもArduinoスケッチを書き込めるようなので、モジュール単体だけでセンサーなどの扱いとネットワーク接続の両方ができる、なかなか万能な子です。
今回使用するモジュールについて
ESP-WROOM-02は、値段も安くサイズも小さいのですが、それ単体だとESP8266とシリアル通信を行うためのコネクタや、電圧変換を行う仕組みなどの部分は自分で作らなければなりません。今回は、その辺りをまるっと解消してくれている「ESP-WROOM-02開発ボード」を使うことにしました。
準備
準備作業としてはピンヘッダをはんだ付けするだけです。5Vを3.3Vに出力してくれるレギュレータ機能も持っているので、PCとのシリアル通信には搭載されているコネクタにマイクロUSBを接続するだけで、すぐに利用ができます。完全にこのボードひとつだけで完結してくれます。
シリアル通信の確認
ピンヘッダをはんだ付けしたESP-WROOM-02をブレッドボードに挿し、マイクロUSBを使ってMacと接続します。この状態で給電もできているので、シリアルモニターからシリアル通信を行ってみます。 Arduino > Tools > Port から、接続しているUSB(/dev/cu.usbserial-xxxxxx)を選択します。シリアルモニターを開いて、速度を115200bpsにし、改行コードを「Both NL & CR」に変更します。 ESP-WROOM-02のリセットボタンを押すと文字化けデータの後に「ready」と表示されればシリアル通信ができているので、コマンド入力欄に「AT」と入力して送信すると「OK」と返してきます。これでATコマンドのやりとりも確認できました。
もう少しATコマンドを叩いてみる
さらに、いくつかのATコマンドを試してみます。
MACアドレスの確認コマンド
AT+CIPSTAMAC?
+CIPSTAMAC:"xx:xx:xx:xx:xx:xx"
OK
MACアドレスなどでネットワーク制限がかかっている場合には、こちらでMACアドレスが取得可能です。
Station mode
AT+CWMODE=1 (Station Mode)
AT+CWMODE=2 (SoftAP Mode)
AT+CWMODE=3 (Station&SoftAP Mode)
パラメータによって、モードを変換できるようです。今回は
AT+CWMODE=3
OK
としてみました。
SSIDとパスワードを入力してAPに接続
AT+CWJAP="SSID","PassWord"
でWi-Fiに接続可能です。接続を試してみたところ、
AT+CWJAP="xxxxx","xxxxx"
WIFI DISCONNECT
WIFI CONNECTED
WIFI GOT IP
OK
となりました。
IPアドレスやアクセスポイントのMACアドレスの取得
AT+CIFSR
+CIFSR:APIP,"xxx.xxx.xxx.xxx"
+CIFSR:APMAC,"xx:xx:xx:xx:xx:xx"
+CIFSR:STAIP,"xxx.xxx.xxx.xxx"
+CIFSR:STAMAC,"xx:xx:xx:xx:xx:xx"
OK
IPアドレスやMACアドレスはこれで確認できます。先程、ステーションモードを3にしたので、子機モードとソフトAPモードの2種類の情報が返されてきました。
通信速度を変える
AT+UART_DEF=9600,8,1,0,0
OK
Arduinoとのシリアル通信を9600bpsで行うので、これで変更しておきます。
今回作ってみる仕組み
前述の通り、ESP8266自体にArduinoスケッチを書き込めるので、このESP-WROOM-02だけでも完結できるのですが、今回はArduinoからESP-WROOM-02を単純にWi-Fiモジュールとしてだけ使うような形にしてみることにしてみます。タクトスイッチを押すとURLにアクセスし、戻ってきたJSONの値を解析するような構成にしてみました。
配線
Arduino側
Arduino | 接続先 | 備考 |
---|---|---|
D13ピン | ESP-WROOM-02 RX | ソフトウェアシリアル通信用 |
D12ピン | ESP-WROOM-02 TX | ソフトウェアシリアル通信用 |
D3ピン | タクトスイッチ | スイッチON/OFF監視 |
5Vピン | ブレッドボード + | ESP-WROOM-02電源供給 |
GNDピン | ブレッドボード - | |
GNDピン | ブレッドボード - |
ESP-WROOM-02側
ESP-WROOM-02 | 接続先 | 備考 |
---|---|---|
VIN | ブレッドボード + | Arduinoからの電源供給 |
GND | ブレッドボード - | |
5V | ブレッドボード + | タクトスイッチ電源供給 |
配線図
スケッチ
スケッチは、Arduino側に書き込みますので、ボード選択もArduinoにしておきます。setup関数内でWi-Fiのコネクションを張り、タクトスイッチが押されたら指定のURLにアクセスし、JSONのresultを判別するような仕組みにしています。JSONの解析には、ArduinoJsonというライブラリを使用しました。
#include <softwareserial.h>
#include <arduinojson.h> //Json Parser Library
#define SSID "xxxxxxxxxx"
#define PASSWORD "xxxxxxxxxx"
#define HOST_URL "xxxxxxxxxx" //Don't include space
#define ACCESS_DIR "xxxxxxxxxx" //Program Directory
#define HOST_PORT 80
#define USER_AGENT "ESP8266" //Set Free
#define TO_TX_PIN 12 //Arduino 13pin to ESP8266 TX
#define TO_RX_PIN 13 //Arduino 12pin to ESP8266 RX
#define SERIAL_WAIT_TIME 5000
#define SWITCH_PIN 3
int buttonState = 0;
SoftwareSerial esp8266Serial(TO_TX_PIN, TO_RX_PIN);
void setup() {
//Serial Setting
Serial.begin(9600);
esp8266Serial.begin(9600);
esp8266Serial.setTimeout(SERIAL_WAIT_TIME);
Serial.println("--Setup Start--");
//WiFi Setting
bool setupFinish = false;
do {
Serial.println("Try Connect WiFi");
setupFinish = setupWiFi();
if (setupFinish) {
Serial.println("Connected");
} else {
Serial.println("Not Connected");
}
} while(setupFinish == 0);
//Switch Setting
pinMode(SWITCH_PIN, INPUT);
Serial.println("--Setup End--");
}
void loop() {
//Trigger Button
buttonState = digitalRead(SWITCH_PIN);
if (buttonState == HIGH) {
if (sendRequest()) {
sendATCommand("AT+CIPCLOSE", 0);
} else {
Serial.println("Request Failed");
}
}
}
bool setupWiFi() {
//AT+RST > Reset
//AT+CWJAP="SSID","PASSWORD" > WiFi-Connect
if(sendATCommand("AT+RST", SERIAL_WAIT_TIME)) {
String wifiConnectCmd = "AT+CWJAP=\"";
wifiConnectCmd += SSID;
wifiConnectCmd += "\",\"";
wifiConnectCmd += PASSWORD;
wifiConnectCmd += "\"";
return sendATCommand(wifiConnectCmd, SERIAL_WAIT_TIME);
} else {
return false;
}
}
bool sendATCommand(String cmd, int waitTime) {
//Serial Command Send
esp8266Serial.print(cmd);
esp8266Serial.print("\r\n");
//Command Log
Serial.print("AT Command > ");
Serial.println(cmd);
delay(waitTime);
//Response Check From Serial Buffer
if(esp8266Serial.find("OK")) {
Serial.println("OK");
return true;
} else {
Serial.println("NG");
return false;
}
}
bool sendRequest() {
//Establish TCP Connection
//AT Command > AT+CIPSTART="TCP","HOST_NAME",HOST_PORT
String tcpConnectCmd = "AT+CIPSTART=\"TCP\",\"";
tcpConnectCmd += HOST_URL;
tcpConnectCmd += "\",";
tcpConnectCmd += HOST_PORT;
sendATCommand(tcpConnectCmd, SERIAL_WAIT_TIME);
//Header Info
String requestHeader = "GET ";
requestHeader += ACCESS_DIR;
requestHeader += " HTTP/1.1\r\n";
requestHeader += "Host: ";
requestHeader += HOST_URL;
requestHeader += ":";
requestHeader += HOST_PORT;
requestHeader += " User-Agent: ";
requestHeader += USER_AGENT;
requestHeader += " Connection: close ";
requestHeader += "\r\n\r\n";
Serial.println(requestHeader);
//Send Data to Host
//AT Command > AT+CIPSEND=header.length
String sendDataCmd = "AT+CIPSEND=";
sendDataCmd += requestHeader.length();
sendATCommand(sendDataCmd, SERIAL_WAIT_TIME);
//Start Transmission
if(esp8266Serial.find(">")) {
//Access to Host
esp8266Serial.print(requestHeader);
delay(500);
//Data Receive
if(esp8266Serial.available()) {
//Get Content Data
String responseData;
//Response Header Trim
//Until the blank line is the response header
while(esp8266Serial.available()){
responseData = esp8266Serial.readStringUntil('\r');
responseData.trim();
if (responseData.length() == 0) {
break;
} else {
Serial.println(responseData);
}
}
//Response Body = JSON Data Get
while(esp8266Serial.available())
{
responseData = esp8266Serial.readStringUntil('\r');
responseData.trim();
Serial.println(responseData);
}
//JSON Data Parse
const int BUFFER_SIZE = JSON_OBJECT_SIZE(4) + JSON_ARRAY_SIZE(1);
StaticJsonBuffer<buffer_size> jsonBuffer;
char json[responseData.length() + 1];
responseData.toCharArray(json, sizeof(json));
JsonObject& root = jsonBuffer.parseObject(json);
if (!root.success()) {
Serial.println("Parse failed");
return false;
}
//{"result":"OK"}
const char* result = root["result"];
Serial.println(result);
Serial.println();
if (strcmp(result, "OK") == 0) {
Serial.println("Result OK");
return true;
} else {
Serial.println("Result NG");
return false;
}
} else {
Serial.println("Data Not Received");
return false;
}
} else {
Serial.println("Transmission Failed");
return false;
}
}
感想
ESP8266は、Arduinoスケッチも書き込めて値段も安いということもあり、とても扱いやすいモジュールなのですが、どうやらデフォルトバージョンではATコマンドがSSL通信には対応していないようで、そこだけ惜しいところです。とはいえ、SSL通信を使わない、または他の代替手段で対応してしまうのであれば、現時点では非常に有用性の高いモジュールと言えそうです。