WIFI-TNGとESP-WROOM-02で始めるWIFI Arduino

さて、Advent Calendarですよ！

**めりーくりすまーす！！！**

![いつもの謎画像](http://img.dfm.lrv.jp/wifitng/xmas.jpg)

Arduinoも遂に無線の時代に突入！！
そこで、WIFI-TNGだ！というわけで、今回の記事です。

# WIFI-TNGとは?

![WIFI-TNG](http://img.dfm.lrv.jp/wifitng/wifitng.png)

[ESP-WROOM-02（ESP8266EX搭載モジュール）](http://akizukidenshi.com/catalog/g/gM-09607/)は大人気のモジュールなのですが、外部IOのピン間隔が狭く、[変換基板](http://akizukidenshi.com/catalog/g/gP-09715/)などを使わないと、ブレッドボードやユニバーサル基板で使えません。
さらにArduinoからスケッチの書き込みを行うには、[USBシリアル変換モジュール](http://akizukidenshi.com/catalog/g/gK-06894/)も必要になります。

人気がある割には少しハードルが高いなぁ、というのが正直な感想でした。

そんな時に、作者の[@morecat_lab](https://twitter.com/morecat_lab)さんから頂いたのがWIFI-TNGです。
WIFI-TNGは、[@morecat_lab](https://twitter.com/morecat_lab)さんオリジナルのESP-WROOM-02用基板で、ESP-WROOM-02とFTDI231Xを1枚のボードにコンパクトに収めることで、まるでArduino UNOのような感覚で使うことができるボードが作れます。

WIFI-TNGの一般公開・販売はまだ始まっていないようですが、少しフライングして紹介させてください。

## WIFI-TNGの作成

作り方や作るのに必要な部品などについては[『ESP8266をArduino環境で使う』by @morecat_labさん](http://morecatlab.akiba.coocan.jp/lab/index.php/2015/11/wifi-tng/)を参照しました。
基本は上記サイトの通りに作成しましたが、何点か注意点とか補足とか書いておきます。（おそらく数ヶ月後の自分のためにw）

### 1. レギュレータ

部品表中のLODについては、AZ1117H-ADJが指定されていますが、可変レギュレータに慣れてなかったこともあり、同じサイズの[AZ1086H-3.3](http://akizukidenshi.com/catalog/g/gI-02502/)に変更しました。
これで抵抗を2つ節約もできます。

### 2. FT231X

秋月に[FT231XS](http://akizukidenshi.com/catalog/g/gI-06713/)が置いてありますので、これを使いました。

### 3. コンデンサ

様々なサイズ指定がありますが、無理矢理手持ちの0805サイズのものを付けたら。。。付きましたw

![ムリヤリ](http://img.dfm.lrv.jp/wifitng/cond.png)

> もちろん、推奨はしませんが、何かの参考にでも。

### 4. チップLED

チップLEDのはんだ付け！これマジで難しいです。

> LEDのプラスチックの部分が、あっという間に溶けます。。。

### 5. ジャンパー

[『ESP8266をArduino環境で使う』by @morecat_labさん](http://morecatlab.akiba.coocan.jp/lab/index.php/2015/11/wifi-tng/)の記事にあるジャンパー、なかなか難易度が高いのですが、新しいバージョンの基板では問題解消されていて、ジャンパーは不要になっています。

## その他

> 温度調整機能ハンダごてが無いとベタGND側のハンダ付けが難しくて泣けます。
> というか、まだ持ってないので泣いています。。。

# Arduino IDEから使う準備

次に、Arduino IDEの準備です。
なななななんと！1.6.5以降でないと駄目です。
あと、arduino.orgの1.7.x系もよくわかりません。

[arduino LLCの1.6.5](https://www.arduino.cc/en/Main/OldSoftwareReleases#previous)を使いました。

> 既に1.6.6が出てますが、確認できていません。。。

WIFI-TNGにプログラム（スケッチ）を書き込むには、Arduino IDE 1.6.5に[esp8266/Arduino](https://github.com/esp8266/Arduino)をインストールする必要があります。

もちろん、[esp8266/Arduino](https://github.com/esp8266/Arduino)で紹介されている手順通りにやれますが、下記記事にめちゃめちゃ詳しく書いてありました！

[『技適済み格安高性能Wi-FiモジュールESP8266をArduinoIDEを使ってIoT開発する為の環境準備を10分でやる方法』by azusa9さん](http://qiita.com/azusa9/items/264165005aefaa3e8d7d)

というわけで、ここでは割愛しますw

# 使ってみる

さっそく始めてみます。

## Lチカ

念のため、最初はLチカです。
これは、完全に他のArduinoと同じです。
(UNOとPIN番号がちがうだけ)

```c
#define LED_PIN 4

void setup() {
  pinMode(LED_PIN, OUTPUT);
}
void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  digitalWrite(LED_PIN, LOW);
  delay(1000);
}
```

なんだろ、この安心感。というわけで、続き行きます！

## WiFi経由でLチカ（APモード）

Lチカだけだと面白くないので、早速WIFIならではの機能を使ってみます。
Arduino Yunとか、[Linino One](http://qiita.com/okhiroyuki/items/9c024c6db93a639ee788)とか、全然使ったことのない私にとって無線Arduino初体験です。ドキドキ！

最初は、単純そうなAPモードを試してみます。PCからWIFI-TNGにWIFIで直接繋いで「遠隔Lチカ」です！

![遠隔Lチカ](http://img.dfm.lrv.jp/wifitng/apmode.png)

実はこれ、Arduinoの`File>Examples>ESP8266Wifi>WiFiAccessPoint`を少し改造するだけで出来ます。

```c
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>

const char *ssid = "esp";
const char *password = "12345678";

ESP8266WebServer server(80);

void handleRoot() {
	server.send(200, "text/html", "<h1>You are connected</h1>");
}

void LedOn(){
  server.send(200, "text/html", "<h1>LED is ON</h1>");
  digitalWrite(4,HIGH);
}

void LedOff(){
  server.send(200, "text/html", "<h1>LED is Off</h1>");
  digitalWrite(4,LOW);
}

void setup() {
  pinMode(4,OUTPUT);
	delay(1000);
	Serial.begin(115200);
	Serial.println();
	Serial.print("Configuring access point...");
	WiFi.softAP(ssid, password);
	IPAddress myIP = WiFi.softAPIP();
	Serial.print("AP IP address: ");
	Serial.println(myIP);
	server.on("/", handleRoot);
  server.on("/on/", LedOn);
  server.on("/off/", LedOff);
	server.begin();
	Serial.println("HTTP server started");
}

void loop() {
	server.handleClient();
}
```

WIFIのSSIDから「esp」と書いてあるのを選んで、パスワードに「12345678」を入力して接続します。

![APモード](http://img.dfm.lrv.jp/wifitng/ap.png)

接続後、ブラウザを起動して、`192.168.4.1/on/`と入力！LEDランプが着いたら成功です〜
`192.168.4.1/off/`と入力すればLEDが消えます。

雑ですが、あっと言う間にリモート感のあるものが作れました！

## WiFi経由でLチカ（STAモード）

さて、APモードもいいのですが、これだとネットに繋がらなくなるのでSTAモードでも使いたいですね。

![staモード](http://img.dfm.lrv.jp/wifitng/stamode.png)

STAモードの場合、接続するWIFIルータからDHCPでIPが振られるので、IPアドレスだと接続しにくいですね。
そこで、mDNS（マルチキャストDNS）と言う仕組みを使って、ローカルネットワーク内でだけ有効な名前を使ってアクセスできるようにしましょう。

と書くと、超めんどくさそうですが、そこはArduino！さすが！サンプルがあるので簡単です。

今度は、PCと同じWiFiネットワークにWIFI-TNGを繋いで、`wifi-tng.local`でアクセスできるようにしてみます。

### mDNSで名前を有効にする

mDNSのサンプルはArduinoの`File>Examples>ESP8266mDNS>mDNS_Web_Server`にあります。
![mDNSサンプルの場所](http://img.dfm.lrv.jp/wifitng/mdns_sample.png)

下記のようにすれば良いみたいです。

```c
#include <ESP8266mDNS.h>

void setup(void){
 :
  if (!MDNS.begin("wifi-tng")) {
    Serial.println("Error setting up MDNS responder!");
    while(1) { 
      delay(1000);
    }
  }
 :

  MDNS.addService("http", "tcp", 80);

}
```

これだけで良さそうですね。

### STAモードで他のAPに接続する

今回はAPモードではないので、STAで他のAPに接続するようにしましょう。

```c
void setup(void){

  WiFi.begin(ssid, password);
  WiFi.mode(WIFI_STA);  // Disable Access Point

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

  :

}
```

こんな感じで接続できるようになります。

### こんな感じになりました。

```c
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

const char* ssid = "...";
const char* password = "...";

ESP8266WebServer server(80);

void handleRoot() {
  server.send(200, "text/html", "<h1>You are connected</h1>");
}

void LedOn(){
  server.send(200, "text/html", "<h1>LED is ON</h1>");
  digitalWrite(4,HIGH);
}

void LedOff(){
  server.send(200, "text/html", "<h1>LED is Off</h1>");
  digitalWrite(4,LOW);
}

void setup(void)
{  
  pinMode(4,OUTPUT);
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  WiFi.mode(WIFI_STA);  // Disable Access Point

  Serial.println("");  
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (!MDNS.begin("wifi-tng")) {
    Serial.println("Error setting up MDNS responder!");
    while(1) { 
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
  
  server.on("/", handleRoot);
  server.on("/on/", LedOn);
  server.on("/off/", LedOff);
  server.begin();

  Serial.println("HTTP server started");
  MDNS.addService("http", "tcp", 80);
}

void loop(void)
{
  server.handleClient();
}
```

## せっかくなので、Ajaxにしてみる

さきほどの２つで、とりあえずはURL叩けばLEDが点いたり消えたりするようにはなったのですが、Ajaxにしろよ。という感じです。なので、やってみます。

- wifi-tng/ にアクセスしたら、ON/OFFボタンを表示
- ON / OFF ボタン押したらajaxで通知

こんな感じにしてみましょう。

### index.htmlを返せるようにする

ボタン表示だけの簡単なHTMLとはいえ、さすがに文字列直で返すのは辛いです。
`index.html`を作って、それを読み込んで返すようにしましょう。

#### index.htmlファイルを作成する

HTMLはこんな感じで。↓

```html
<!DOCTYPE html><html><head><meta charset="utf-8"><meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
<title>LED Button</title>
<style>
button{
  font-size:48px;
  width:100%;
  height:120px;
}
</style>
</head>
<body>
<script>
function sendOn(){
  send("/on/");
}
function sendOff(){
  send("/off/");
}
function send(url){
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.send();
}
</script>
<button id="on" onClick=sendOn()>LED ON</button>
<button id="off" onClick=sendOff()>LED OFF</button>
</body></html>
```

これを、`index.html`という名前で保存して、作成するスケッチのフォルダに下記のように（**スケッチ名のフォルダ/data/の下に**）保存しましょう。
今回、スケッチは、`ajax`という名前で作成しています。

![スケッチフォルダの下にindex.htmlを置く](http://img.dfm.lrv.jp/wifitng/htmlpath.png)

次に、Arduino IDEから、`Tools>ESP8266 Sketch Data Upload` を選択します。

![スケッチフォルダの下にindex.htmlを置く](http://img.dfm.lrv.jp/wifitng/upload.png)

必ず、`ajax`スケッチを開いた状態で実施してくださいね！
すると、index.htmlをESP-WROOM-02に転送してくれます。

### ファイルシステムを使おう

index.htmlを読み込むには、ファイルシステムを利用します。

```c
#include <FS.h>` // <- これでファイルシステムが利用可能に

:
  #define BUFFER_SIZE 16384  // <- これでもか！というくらいでかいバッファw
  uint8_t buf[BUFFER_SIZE];

  SPIFFS.begin(); // <- ファイルシステム利用開始！

  File htmlFile = SPIFFS.open(path_root, "r"); // 読み込みモードでファイルOpen

  size_t size = htmlFile.size(); // ファイルサイズが取れます
  htmlFile.read(buf,size);		 // バッファにファイルサイズ分読み込みます。
```

こんな感じでバッファにindex.htmlが読み込まれましたので、あとは`server.send()`で返せばOKです。
やっとサーバーっぽくなって来ました。

![ようやく普通になった](http://img.dfm.lrv.jp/wifitng/blinking.png)

いえい！

スケッチは下記のようになりました。

```c
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h>

const char* path_root   = "/index.html";
const char* ssid        = "....";
const char* password    = "....";
#define BUFFER_SIZE 16384
uint8_t buf[BUFFER_SIZE];

ESP8266WebServer server(80);

void handleRoot(){
  Serial.println("Access");
  server.send(200, "text/html", (char *)buf);
}

boolean readHTML(){
  File htmlFile = SPIFFS.open(path_root, "r");
  if (!htmlFile) {
    Serial.println("Failed to open index.html");
    return false;
  }
  size_t size = htmlFile.size();
  if(size >= BUFFER_SIZE){
    Serial.print("File Size Error:");
    Serial.println((int)size);
  }else{
    Serial.print("File Size OK:");
    Serial.println((int)size);
  }
  htmlFile.read(buf,size);
  htmlFile.close();
  return true;
}

void LedOn(){
  Serial.println("ON");
  digitalWrite(4,HIGH);
  server.send(200, "text/html","OK");
}

void LedOff(){
  Serial.println("OFF");
  digitalWrite(4,LOW);
  server.send(200, "text/html","OK");
}

void setup() {
  pinMode(4,OUTPUT);
  Serial.begin(115200);
  SPIFFS.begin();
  if(!readHTML()){
    Serial.println("Read HTML error!!");
  }
  WiFi.begin(ssid, password);
  WiFi.mode(WIFI_STA);
  Serial.println("Connecting to Access Point");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  if (MDNS.begin("wifi-tng")) {
    Serial.println("MDNS responder started");
  }
  server.on("/", handleRoot);
  server.on("/on/", LedOn);
  server.on("/off/", LedOff);
  server.begin();
  MDNS.addService("http", "tcp", 80);    
}

void loop() {
  server.handleClient();
}
```

# まとめ

ESP-WROOM-02(ESP8266)めちゃめちゃ面白いです！

Arduinoと殆ど同じ使い方で使えて（これはWIFI-TNGと[esp8266/Arduino](https://github.com/esp8266/Arduino)のお陰）、でもWebサーバーっぽくも使えるのでデバイスのコントローラーUIもホストできたりします。
今回は紹介しませんでしたが、[Links2004/arduinoWebSockets](https://github.com/Links2004/arduinoWebSockets)などを使えば、WebSocketsにも対応できたり！

Webで出来るだけやっちゃう系にはタマりません。。

![買い過ぎ](http://img.dfm.lrv.jp/wifitng/many.jpg)

。。調子に乗って10個も買ってしまった。。。w

しかし、WIFI-TNGみたいなボードが無いと、ちょっと使う元気が無いというか、ヒマがないというか、という私みたいな人、結構多いと思います。

やはり、ArduinoはUSBで直接書き込めるから、これだけ人気が出たのだと思います。
WIFI-TNGのようなボードがもっと出てほしいと本気で思いました！

> ESP8266搭載ボード海外は超沢山あるけどTELEC認証がないのが多いんですよね。。。