読者です 読者をやめる 読者になる 読者になる

ESP-WROOM-02(ESP8266)でLチカ(ブラウザからLEDをオンオフ)をSTAモード、固定IPでやってみる

挙動は動画の通り。
www.youtube.com

やってることは以下のサイトをそっくり真似してるだけです。コードもコピペです。インターネットありがたい。

qiita.com
この記事の素晴らしいところは、単なるLチカだけどESP-WROOM-02をAPモードではなくSTAモードで使うことで、操作する側のPC/スマホwifiの接続先をいちいち変えなくてもいいところ。それからブラウザから操作するためのUIをAjaxでつくってるところ。
まさに俺がやりたかったのはこれだよ!って感じです。

が、同じようにやろうとしても、どうしても次の2点だけうまくいきませんでした。何が悪いんだろ。

  1. mDNSでローカルネットワーク内のみのドメイン名を使う →うまくいかない
  2. ファイルシステムを使って別に用意したindex.htmlを返す →うまくいかない

なので、それぞれ代替策をとりました。といっても、ただ諦めただけです。

1に関しては、たしかにDHCPだとルーター再起動等のきっかけでIPアドレスが変わってしまって不便ですが、だったらIPアドレス固定すればええやん、と考えました。想定している用途によりますが、家庭内の無線通信手段としてwifiを使おうとしているだけなら、むしろ固定IPのほうがシンプルに思えます。

2に関しては、あきらめてArduinoのスケッチの中に、UI用のhtmlを書いてしまうことにしました。C++の中にhtmlが書いてあって、そのhtmlの中にJavascriptが書いてあるという気持ち悪さはありますが。


さて、STAモードでESP-WROOM-02wifiアクセスポイントに接続するとき固定IPをつかう方法ですが、調べてみると、どうやらWiFi.config()というのを使うらしい。
arduinoのリファレンスをみると、 デフォルトではDHCPであり、WiFi.config()をつかえば手動で設定できる、ということみたい。


※※※【2016年11月26日追記】※※※
なんとなく疑問が残ったので調べてみたんですが、
https://www.arduino.cc/en/Reference/WiFiConfigにそのまま従うと

WiFi.config(ip, dns, gateway, subnet);

という順で書くのに対して、ESP8266の場合は、

WiFi.config(ip, gateway, subnet, dns);

の順で書き、しかも最後のdns以外は省略できないようです。
参考:

※※※【追記ここまで】※※※


そのあたりを書き加えると、こんな感じのコードになりました。

#include <WiFiClient.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#define LED 13                    //LED点灯に使用するピン
ESP8266WebServer server(80);

void onroot() {
    String msg ;
    msg += "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"><title>LED Button</title></head><body>";
    msg += "<script>";
    msg += "function sendOn(){" ;
    msg += "send(\"/on/\");";
    msg += "document.getElementById(\"LEDstatus\").innerHTML=\"ON!\";";
    msg += "}";
    msg += "function sendOff(){";
    msg += "send(\"/off/\");";
    msg += "document.getElementById(\"LEDstatus\").innerHTML=\"OFF!\";";
    msg += "}";
    msg += "function send(url){";
    msg += "var xhr = new XMLHttpRequest();";
    msg += "xhr.open(\"GET\", url, true);";
    msg += "xhr.send();";
    msg += "}";
    msg += "</script>";
    msg += "<button id=\"on\" onClick=sendOn()>LED ON</button>";
    msg += "<button id=\"off\" onClick=sendOff()>LED OFF</button>";
    msg += "<p id=\"LEDstatus\"></p>";
    msg += "</body></html>";

    server.send(200, "text/html", msg);
}

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

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

void setup() {

    pinMode(LED, OUTPUT);

    Serial.begin(115200);
    Serial.println("");
    Serial.println("ESP8266 Wifi test");

    WiFi.config(IPAddress(192, 168, 0, 99), WiFi.gatewayIP(), WiFi.subnetMask()); //使いたいIPアドレスを指定
    WiFi.begin("xxxxSSIDxxxx", "xxxxPASSWORDxxxx");   //接続先のwifiアクセスポイント
    WiFi.mode(WIFI_STA);

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

    Serial.println("");
    Serial.print("Connected as ");
    Serial.println(WiFi.localIP());

    // Web server setting
    server.on("/", onroot);
    server.on("/on/", LedOn);
    server.on("/off/", LedOff);
    server.begin();
}

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

ご覧の通り、サーバーが返すhtmlの内容が見難いので、msgの中身だけ取り出してみたのが以下。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>LED Button</title>
</head>
<body>
  
  <script>
    function sendOn(){
      send("/on/");document.getElementById("LEDstatus").innerHTML="ON!";
    }
    function sendOff(){
      send("/off/");document.getElementById("LEDstatus").innerHTML="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>
  <p id="LEDstatus"></p>
  
</body>
</html>


ブラウザで見たときの、“ON!”や“OFF!”の表示は、実際のLEDの状態を監視して取得しているわけではなくて、ただ単にボタンがクリックされたら文字を書き換えてるだけです。


早速、ESP-WROOM-02に書き込んで、指定したIPアドレスhttp://192.168.0.99/をブラウザのアドレスバーに入れてEnter。ちゃんとhtmlが返されました。

念のため、ルーターの設定画面でIPアドレスの割当状況を見てみると、192.168.0.99は「*** STATIC IP ADDRESS **」となっていました。
f:id:teramorosu:20161023162829p:plain

例外処理とか全然考えてないので公開するようなもんじゃないですが、最低限これでやりたいこと実現できたよ、という意味で。