趣味の電子工作などの記録。時にLinuxへ行ったり、ガジェットに浮気したりするので、なかなかまとまらない。
RSS icon
  • ESP8266にWebSocketを喋らせてみる

    投稿日 2015年 7月 29日 コメントはありません

    世の中、同じようなことを考える方はいるようで、すでにESP8266+ArduinoIDEでWebSocketライブラリが存在しています。WebSocketが扱えるようになれば、(プログラミングスキルがあれば)クラウド側から好きなタイミングでESP8266に指示をおくることができるようになるはずです。(が、世の中そんなに甘くないんですねぇ〜)

    で、今回見つけたWebSocketライブラリは ESP8266-Websocket です。

    今回の記事はこれのサンプルを動かしてみよう、と苦戦した記録です。作業PCのOSはUbuntu14.10 LTS 64bit、ArduinoIDEのバージョンは1.6.5です。なお、Ubuntuで動かすにあたっては、

    $ sudo addgroup foobar dialout
    ユーザー `foobar' をグループ `dialout' に追加しています...
    ユーザ foobar をグループ dialout に追加
    完了。
    $

    として、/dev/ttyUSB0のアクセス権をユーザーにつけた後、再ログインしないと/dev/ttyUSB0へアクセスできないとしてエラーになります。

    Arduinoのライブラリは ~/Arduino/librariesの下に置けばいいようですので、そこにgitでライブラリを引っ張ってきます。

    ~$ cd ~/Arduino/libraries
    ~/Arduino/libraries$ git clone https://github.com/morrissinger/ESP8266-Websocket
    Cloning into 'ESP8266-Websocket'...
    remote: Counting objects: 286, done.
    remote: Total 286 (delta 0), reused 0 (delta 0), pack-reused 286
    Receiving objects: 100% (286/286), 105.19 KiB | 0 bytes/s, done.
    Resolving deltas: 100% (103/103), done.
    Checking connectivity... done.
    ~/Arduino/libraries$ 
    

    その後、ArduinoIDEで「スケッチ」→「Include Library」→「Manage Libraries」で右上の「Filter your search」で「ESP8266-Websocket」と入力して「INSTALLED」になっていることを確認します。

    scrn1

    次に、WebSocketClientのデモを動かしてみます。

    「ファイル」→「スケッチの例」→「ESP8266-Websocket」→「WebSocketClient_Demo」を選択します。

    scren2

    ソースの冒頭の

    const char* ssid     = "SSID HERE";
    const char* password = "PASSWORD HERE";

    の部分に自分の無線LANのESSIDとパスキーを入力してから、名前を付けて保存します。

    このライブラリはおそらくWindows環境で作成されたのでしょう。Linux環境でビルドしようとすると、ファイル名の大文字小文字で失敗します。そのため、ライブラリの中の以下の部分を修正します。

    WebSocketClient.h と WebSocketServer.h の

    #include "String.h"

    #include "string.h"

    に、

    WebSocketServer.cpp と WebSocketClient.cppの

    #include "base64.h"

    #include "Base64.h"

    とします。

    これでビルドが通るようになりましたが、それでもコネクションに失敗します。禁断のgoto文で接続しに行く部分のみを繰り返すと、何回目か以降は通るようです。ライブラリのWebSocketClient.cppの冒頭にデバッグのための#define文があるので、ここをコメントを外すとデバッグメッセージが出るのですが、これでもハンドシェークの途中で止まっていることはわかるものの、それ以上はなんともわかりません。
    これ以上は間にLANアナライザを入れてみてパケット解析しつつ、RFCを読んで何かおかしいのか調べるしかなさそうです。

    以下は、現時点でのサンプルプログラムを改造したものです。

    #include <ESP8266WiFi.h>
    #include <WebSocketClient.h>
    
    const char* ssid     = "xxxxxxxxxxxxxxxx";
    const char* password = "xxxxxxxxxxxxxxxx";
    char path[] = "/";
    char host[] = "echo.websocket.org";
      
    WebSocketClient webSocketClient;
    
    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    
    void setup() {
      Serial.begin(115200);
      delay(10);
    
      // We start by connecting to a WiFi network
    
      Serial.println();
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);
      
      WiFi.begin(ssid, password);
      
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
    
      Serial.println("");
      Serial.println("WiFi connected");  
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    
      delay(5000);
      
    RETRY:
      // Connect to the websocket server
      IPAddress remote_addr;
      if(!WiFi.hostByName(host,remote_addr)){
        Serial.println("Cannot resolve hostname");
        while(1){}
      } else {
        Serial.println("hostname resolved");
      }
      
      if (client.connect(remote_addr, 80)) {
        Serial.println("Connected");
      } else {
        Serial.println("Connection failed.");
        goto RETRY;
        while(1) {
          // Hang on failure
        }
      }
    
      // Handshake with the server
      webSocketClient.path = path;
      webSocketClient.host = host;
      if (webSocketClient.handshake(client)) {
        Serial.println("Handshake successful");
      } else {
        Serial.println("Handshake failed.");
        while(1) {
          // Hang on failure
        }  
      }
    
    }
    
    
    void loop() {
      String data;
    
      if (client.connected()) {
        
        webSocketClient.getData(data);
        if (data.length() > 0) {
          Serial.print("Received data: ");
          Serial.println(data);
        }
        
        // capture the value of analog 1, send it along
        pinMode(1, INPUT);
        data = String(analogRead(1));
        
        webSocketClient.sendData(data);
        
      } else {
        Serial.println("Client disconnected.");
        while (1) {
          // Hang on disconnect.
        }
      }
      
      // wait to fully let the client disconnect
      delay(3000);
      
    }

    WebSocketClient.cppをみると、サーバ側からのヘッダの解釈の実装がまだまだであることがわかります。ひとつの可能性として、どうやらここで止まっていそうです。もうひとつは、パケットの受信バッファの処理がどうも変な感じがします。

    いずれにせよ、このライブラリはまだそのままでは使えるものではなさそうな感じです。(ま、よくみると色々と制約があるよ、って書いてあるんですけどね)


    コメントをどうぞ(日本語のみ/Only in Japanese)

    日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)