オブジェの LED カラー を スマホ ブラウザ で WiFi リアルタイム コントロール してみた

記事公開日:2016年12月16日

スポンサーリンク

こんばんは。

前回の記事では NeoPixel フルカラー LED とマイコンを使って、紙や光ファイバーで卓上オブジェを作りました。

今回は、更に一歩進んで、スマホのブラウザから、Wi-Fi の WebSocket 通信を使って、リアルタイムに色を変えたり、明るさを変えたり、回転スピードを調整したりしてみたいと思います。
要するに、ラジコンみたいな無線リモートコントロールをスマホでやってしまおうというものです。

まずは、ESPr Developer と NeoPixel Ring だけの以下の動画をご覧ください。

いかがでしょうか。
かなり、リアルタイムで色調整ができますね。

次に、前回の記事で作った光ファイバーオブジェを使うとこんな感じになります。

クリスマスやお正月でオブジェを作って、その場の雰囲気に合わせてカラーをスマホでリアルタイムに変えるっていう演出もできそうです。

これは、Webページ制作で使うHTMLタグのカラーピッカー(カラーコード抽出)を使用することで、意外と簡単に実現できました。
こんな感じのHTMLタグです。

<input type="color" value="#FF1234" >

ただ、このカラーピッカーはスマホやパソコンのオペレーティングシステム( OS )によって操作が異なるため、注意が必要です。
以下、ブラウザのHTML5 カラーピッカーの対応状況は以下の通りです。

  • Android 6.0.1  Google Chrome — ◎
  • Android 5.0.2  Google Chrome — ◎
  • Android 4.2.2  Google Chrome — ◎
  • Android 5.0.2  Firefox  — ×WebSocket すら接続できない
  • Windows 10 Google Chrome — ◎
  • Windows 10 Edge — ×WebSocket すら接続できない
  • iOS 10.2  Safari — △テキスト入力のみ

Web上ではこんな感じに表示されます。
↓これをクリックするとカラーピッカーが表示されます。

動画のように表示されなければ、そのブラウザは対応してません。
OSによるカラーピッカーの表示情況は最後の方に掲載してますので、ご覧ください。

動画でもあるように、Rotation OFF ボタンを押すとカラーピッカーボタンのValue値が更新され、色が変わります。
つまり、回転ストップした位置のLEDの現在色がブラウザに表示されるわけです。
今回の目玉の機能です。
我ながらなかなか画期的だと思いました。

これができれば、プログラムをいちいち書き換えないでも、リアルタイムに色が変えられるので、その場の雰囲気にスピーディーに合わせられますね。

ところで、前回前々回の記事でもお伝えしましたが、NeoPixel フルカラーLED は5V駆動です。
しかし、今回はスマホとWi-Fi通信するということで、スイッチサイエンスさんの ESPr Developer のみ使用します。
Arduino UNO では動作しません。

NeoPixel のロジック動作電圧範囲外なので、うまく動かないこともありえます。
そのことを十分ご理解した上で使ってみてください。

では、これについて順に説明していきます。

1.準備するもの

オブジェ側は前回の記事と全く同じですので、それを参照してください。
(今回はArduino UNO は使えませんのでご了承ください)

また、今回はそれに加えて、2.4GHz 無線LAN ( Wi-Fi ) ルーター環境と、操作するためのスマートフォンが必要です。

スマートフォンは出来るだけ最新機種で、高速CPU で、多くのメモリのある高スペックのものを使用してください。
OS はAndroid で、ブラウザはGoogle Chrome 推奨です。

ESP8266 チップの処理能力にも問題がありますが、通信環境も大きく影響します。
明るさ調整や、スピード調整のようなスライダーを使うと、データが連続送信されますので、通信トラフィックが混雑して、途中でフリーズする可能性があります。

Wi-Fi ルーター(アクセスポイント)もできるだけ高スペックのものを使用してください。
私は、自宅のケーブルテレビ有線ルーターに、コンパクトで持ち運び便利な、Wi-Fi ホテル用ルーターを使ってます。
以下の製品は一世代前のものですが、ハードな通信をしなければ、これで意外とイケます。
Amazon.co.jp
もっと高速通信のものを使えば、良いかとも思うのですが、それだと ESP-WROOM-02 ( ESP8266 )側の処理能力が追い付きませんので、これくらいがよろしいかと思ってます。

2.組み立て、接続等

前回の記事の4項目まで済ませておいてください。

また、Wi-Fi 環境を準備しておき、ルーターのSSID やパスワードは事前に設定しておいてください。

3.Arduino IDE 設定

Arduino IDE は必ず Arduino.cc ページのものを使用してください。
動作確認済みのバージョンは 1.6.13 ( 2016/12/15 時点 ) です。

そして、Arduino IDE には ESP8266ボードをインストールしておいてください。
インストール方法は以下のページを参照してください。

Arduino IDE に Staging(Stable)版ESP8266 ボードをインストールする方法

4.Arduino IDE へ SPIFFSファイルシステムインストール

SPIFFSファイルシステムとは、ESPr Developer ( ESP-WROOM-02, ESP8266 ) のフラッシュにHTMLファイルなどを保存できるようにするための、Arduino IDE 用の ESP8266 プラグインです。
これのインストール方法は以下のページを参照してください。

Arduino IDE に ESP8266 SPIFFS ファイルシステムアップローダーをインストールする方法

これで、ESPr Developer ( ESP-WROOM-02, ESP8266 ) には最大3MB までのユーザーデータを保存しておくことができます。

5.Adafruit NeoPixel ライブラリのインストール

Adafruit の NeoPixel ライブラリは以下のページを参照してインストールしておいてください。

NeoPixel と紙で フルカラー LED イルミネーション オブジェを作ってみた

6.EasyWebSocket_SPIFFS beta ver 1.48 をインストール

当方の自作ライブラリ、EasyWebSocket_SPIFFS をインストールします。
これは、Arduino IDEの ESP8266チップ用ライブラリで、スマホやPCのブラウザで双方向リアルタイム通信 ( WebSocket通信 ) を行うためのものです。

今回はバージョンアップして、Beta ver 1.48 となりました。
GitHub のこちらのページ にありますので、ZIPファイルをダウンロードしてください。

インストールする前に必ず行っていただきたいのは、以前にインストールした EasyWebSocket ライブラリは、フォルダごと削除して、アンインストールしておいてください。
Windows 10 ならば、ファイルパスは以下のようなところにあると思います。

C:\Users\xxxx\Documents\Arduino\libraries

xxxx はご自分のPCのユーザーネームです。

次に、ダウンロードしたZIPファイルをArduino IDE にインストールする方法は以下のページを参照してください。
ZIPファイルを簡単にインストールする方法があります。

GitHubにある ZIP形式ライブラリ のインストール方法

7.HTMLヘッダファイルをESP8266 へ SPIFFSアップロードする

EasyWebSocketライブラリの Beta ver 1.48 では、HTMLヘッダファイルを一新しました。

今までは、ESPr Developer ( ESP-WROOM-02, ESP8266 ) のWi-Fi ローカルIPアドレスが変わる度にSPIFFSファイルを書き換えてアップロードしていました。

ローカルIPアドレスが変わってしまう場合というのは、ルーター側でIPアドレスを自動割り当てに設定していて、停電が起きた時や、ルーターの電源を立ち上げ直した時に、ルーター側が自動で再割り当てを行ってしまう為に、アドレスが変わってしまうのです。
その度に書き換えるのがとても面倒だったので、ESP8266側がローカルIPアドレスを自動で読み取るようにしました。
それに伴って、WebSocket通信用のHTMLヘッダを分割して、ESP8266側で取得したIPアドレスを合体(マージ)させてスマホのブラウザへ送信するようにしました。

と、いうことで、その分割ファイルはサンプルスケッチの中にあります。
まず、下図のように「スケッチの例」の Auto_Local_IP_sample を開きます。

ColorPicker10

次に、「スケッチのフォルダを表示」を開きます。

ColorPicker11

下図の様にそのフォルダの data フォルダを開きます。
ColorPicker12

下図の様に、2つのファイルを使います。
HTMhead1.txt
HTMhead2.txt

ColorPicker13

この2つのファイルは合計で 11kB しかありませんので、Arduino IDE のESP8266ボード設定は
Flash Size: ” 4M ( 1M SPIFFS ) ” 
で良いです。

USBシリアルで ESPr Developer ( ESP-WROOM-02, ESP8266 ) へのSPIFFSアップロード方法は以下のページをご覧ください。

Arduino IDE に ESP8266 SPIFFS ファイルシステムアップローダーをインストールする方法

4M ( 3M SPIFFS ) でアップロードしたい場合は、USBシリアルではアップロードできませんので、その場合はWi-Fi でOTAアップロードということになります。
それは以下のページを参照してください。

4M ( 3M SPIFFS ) をシリアルポートでアップロードできない場合のトラブルシューティング

USBの電流量が問題になる場合がありますので、USBハブはダメです。
必ずパソコン直挿しにしてください。

8.スケッチ(プログラム)の入力

では、スケッチを入力していきます。
ライセンスは、Arduino core for ESP8266 ライブラリは
LGPL ver2.1 です。
ですから、私の自作 EasyWebSocket ライブラリは
LGPL ver2.1 になります。
因みに、Adafruit ライブラリは、
LGPL ver3. です。

では、以下のスケッチをIDEに入力してみてください。

/*  
 *  Required EasyWebSocket_SPIFFS library beta ver 1.48
 *  License of EasyWebSocket_SPIFFS libraries is LGPL ver2.1
 *  License of Adafruit NeoPixel libraries is LGPL ver3.
 *  Reference: <http://www.gnu.org/licenses/>
 */
#include <Adafruit_NeoPixel.h>
#include <EasyWebSocket.h> //※beta ver 1.48が必要です
#include <ESP8266WiFi.h>
#include <Hash.h>

const char* ssid = "xxxx"; //ご自分のルーターのSSIDに書き換えてください
const char* password = "xxxx"; //ご自分のルーターのパスワードに書き換えてください

const char* HTM_head_file1 = "/HTMhead1.txt"; //HTMLヘッダファイル1
const char* HTM_head_file2 = "/HTMhead2.txt"; //HTMLヘッダファイル2

//シリアル通信GPIOピン番号と、LED素子の最大数定義
enum { PIN = 5, MAXPIXELS = 12 };

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(MAXPIXELS, PIN, NEO_GRB + NEO_KHZ800);
EasyWebSocket ews; //EasyWebSocketライブラリ クラス名定義

IPAddress LIP; //ESP-WROOM-02(ESP8266) ローカルIPアドレス自動取得用

String html_str1 = ""; //スマホブラウザに表示させるHTMLタグ文字列を定義
String html_str2 = "";
String html_str3 = "";
String html_str4 = "";
String html_str5 = "";
String html_str6 = "";
String html_str7 = "";

int PingSendTime = 30000; //スマホとWebSocket接続されているか確認するためのPing送信する間隔
String ret_str; //スマホから送信されてくる文字列を定義

//NeoPixel LED三原色定義および初期化
uint8_t red[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t green[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t blue[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

//現在表示されているNeoPixelのRGBを定義および初期化
uint8_t red_now[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t green_now[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t blue_now[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

//隣のLEDとの明るさの差をRGBそれぞれについて定義および初期化
float red_dif[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
float green_dif[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
float blue_dif[MAXPIXELS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

int cnt = 0; //256段階でLEDをフェードさせるためのカウント

//LED点灯を回転させるための定義
boolean Rot_ON = false;
uint32_t RotationTime;
uint8_t RotationSpeed = 0;

//********************セットアップ***********************************
void setup() {
  //ブラウザへ送信するHTML body要素部分を作る
  //※Canvas_Sliderは一つのString変数に2つ以内
  html_str1 = "<body style='background:#000; color:#fff;'>\r\n";
  html_str1 += "<font size=3>\r\n";
  html_str1 += "ESP-WROOM-02(ESP8266)\r\n";
  html_str1 += "<br>\r\n";
  html_str1 += "EasyWebSocket 1.48 Sample\r\n";
  html_str1 += "</font><br>\r\n";
  html_str1 += ews.EWS_BrowserSendRate();
  html_str1 += "<br>\r\n";
  html_str1 += ews.EWS_Status_Text2("WebSocket Status","#555555", 20,"#FF00FF");
  html_str1 += "<br><br>\r\n";
  html_str2 += ews.EWS_On_Momentary_Button("OFF", "ALL-Clear", 100,25,15,"#FFFFFF","#FF0000");
  html_str2 += "<br><br>\r\n";
  html_str2 += ews.EWS_On_Momentary_Button("RotON", "Rotatin ON", 150,25,15,"#FFFFFF","#005500");
  html_str2 += "<br><br>\r\n";
  html_str2 += ews.EWS_On_Momentary_Button("rotOFF", "Rotation OFF", 150,25,15,"#FFFFFF","#000055");
  html_str2 += "<br><br>\r\n";
  html_str3 += "Brightness.\r\n";
  html_str3 += ews.EWS_Canvas_Slider_T("Brightness",255,40,"#777777","#ffff00");
  html_str3 += "<br><br>\r\n";
  html_str3 += "Speed.\r\n";
  html_str3 += ews.EWS_Canvas_Slider_T("Speed",200,40,"#777777","#7777ff");
  html_str3 += "<br><br>\r\n";
  html_str4 += ews.Color_Picker(  0,  75, "#000000", "LED08");
  html_str4 += ews.Color_Picker(  0, 130, "#000000", "LED09");
  html_str4 += ews.Color_Picker( 30, 160, "#000000", "LED10");
  html_str4 += ews.Color_Picker( 60, 190, "#000000", "LED11");
  html_str4 += ews.Color_Picker( 90, 190, "#000000", "LED00");
  html_str4 += ews.Color_Picker(120, 160, "#000000", "LED01");
  html_str5 += ews.Color_Picker(150, 130, "#000000", "LED02");
  html_str5 += ews.Color_Picker(150,  75, "#000000", "LED03");
  html_str5 += ews.Color_Picker(120,  40, "#000000", "LED04");
  html_str5 += ews.Color_Picker( 90,  10, "#000000", "LED05");
  html_str5 += ews.Color_Picker( 60,  10, "#000000", "LED06");
  html_str5 += ews.Color_Picker( 30,  40, "#000000", "LED07");
  html_str6 += "<br><br><br><br><br><br><br><br><br><br><br><br>\r\n";
  html_str7 += ews.EWS_WebSocket_Reconnection_Button2("WS-Reconnect", "grey", 200, 40, "black" , 17);
  html_str7 += "<br><br>\r\n";  
  html_str7 += ews.EWS_Close_Button2("WS CLOSE", "#ccc", 150, 40, "red", 17);
  html_str7 += ews.EWS_Window_ReLoad_Button2("ReLoad", "#ccc", 150, 40, "blue", 17);
  html_str7 += "</body>\r\n</html>\r\n";

  ews.AP_Connect(ssid, password); //ルーター(アクセスポイント)と接続

  LIP = WiFi.localIP(); //ESP8266のローカルIPアドレスを自動取得
  
  pixels.begin(); // This initializes the NeoPixel library.
  pixels.setBrightness(255); //Max 255

  RotationTime = millis();
}
//********************メインループ***********************************
void loop() {
  ews.EWS_Dev_AutoLIP_HandShake_str(HTM_head_file1, LIP, HTM_head_file2, html_str1, html_str2, html_str3, html_str4, html_str5, html_str6, html_str7);
  
  int i;

  if(ret_str != "_close"){   
    ret_str = ews.EWS_ESP8266CharReceive(PingSendTime); //EasyWebSocketライブラリ。ブラウザから文字列受信
    
    if(ret_str != "\0"){
      Serial.println(ret_str);
      if(ret_str != "Ping"){
        uint8_t ws_data = (ret_str[0]-0x30)*100 + (ret_str[1]-0x30)*10 + (ret_str[2]-0x30);
        switch(ret_str[4]){
          case 'B':
            pixels.setBrightness(ws_data);
            for(i=1; i<MAXPIXELS; i++){
              pixels.setPixelColor(i, pixels.Color(red_now[i], green_now[i], blue_now[i])); //NeoPixelライブラリ
            }
            pixels.show();
            break;
          case 'S':
            RotationSpeed = round(float((200-ws_data)/20));
            break;
          case 'O':
            for(i=0; i<MAXPIXELS; i++){
              red[i] = 0; green[i] = 0; blue[i] = 0;
              red_now[i] = 0; green_now[i] = 0; blue_now[i] = 0;
              red_dif[i] = 0; green_dif[i] = 0; blue_dif[i] = 0;
              pixels.setPixelColor(i, pixels.Color(red[i], green[i], blue[i])); //NeoPixelライブラリ
            }
            pixels.show();
            WebSocket_Browser_ColButton_Value_Send("LED", MAXPIXELS, red, green, blue);
            break;
          case 'R':
            Rot_ON = true;
            Serial.print("Rot_ON="); Serial.println(Rot_ON);
            RotationTime = millis();
            break;
          case 'r':
            Rot_ON = false;
            Serial.print("Rot_ON="); Serial.println(Rot_ON);
            WebSocket_Browser_ColButton_Value_Send("LED", MAXPIXELS, red_now, green_now, blue_now);
            break;
          case 'L':
            uint16_t led_num = (ret_str[7]-0x30)*10 + (ret_str[8]-0x30);
            red[led_num] = (ret_str[10]-0x30)*100 + (ret_str[11]-0x30)*10 + (ret_str[12]-0x30);
            green[led_num] = (ret_str[14]-0x30)*100 + (ret_str[15]-0x30)*10 + (ret_str[16]-0x30);
            blue[led_num] = (ret_str[18]-0x30)*100 + (ret_str[19]-0x30)*10 + (ret_str[20]-0x30);

            red_dif[0] = float(red[0] - red[11])/256;
            green_dif[0] = float(green[0] - green[11])/256;
            blue_dif[0] = float(blue[0] - blue[11])/256;
            
            for(i=1; i<MAXPIXELS; i++){
              red_dif[i] = float(red[i] - red[i-1])/256;
              green_dif[i] = float(green[i] - green[i-1])/256;
              blue_dif[i] = float(blue[i] - blue[i-1])/256;
            }

            red_now[led_num] = red[led_num];
            green_now[led_num] = green[led_num];
            blue_now[led_num] = blue[led_num];
            
            cnt = 0;

            pixels.setPixelColor(led_num, pixels.Color(red[led_num], green[led_num], blue[led_num])); //NeoPixelライブラリ
            pixels.show(); //NeoPixelライブラリ
            
            Serial.print("led_num= "); Serial.println(led_num);
            Serial.print("red = "); Serial.println(red[led_num]);
            Serial.print("green = "); Serial.println(green[led_num]);
            Serial.print("blue = "); Serial.println(blue[led_num]);
            Serial.print("red_dif[0]="); Serial.println(red_dif[0]);
            break;
        }
        ret_str = "";
      }
    }     
  }else if(ret_str == "_close"){
    ret_str = "";
  }
  
  if(Rot_ON){
    if(millis() - RotationTime > RotationSpeed){
      int16_t rr, gg, bb;
      for(i=0; i<MAXPIXELS; i++){
        rr = red[i] - round(red_dif[i] * cnt);
        if(rr > 255){
          red_now[i] = 255;
        }else if(rr < 0){
          red_now[i] = 0;
        }else{
          red_now[i] = rr;
        }
        gg = green[i] - round(green_dif[i] * cnt);
        if(gg > 255){
          green_now[i] = 255;
        }else if(gg < 0){
          green_now[i] = 0;
        }else{
          green_now[i] = gg;
        }
        bb = blue[i] - round(blue_dif[i] * cnt);
        if(bb > 255){
          blue_now[i] = 255;
        }else if(bb < 0){
          blue_now[i] = 0;
        }else{
          blue_now[i] = bb;
        }
        pixels.setPixelColor(i, pixels.Color(red_now[i], green_now[i], blue_now[i])); //NeoPixelライブラリ
      }
      pixels.show(); //NeoPixelライブラリ

      cnt++;
      
      if(cnt == 256){
        uint8_t dummy_red[MAXPIXELS], dummy_green[MAXPIXELS], dummy_blue[MAXPIXELS];
        for(i=0; i<MAXPIXELS; i++){
          dummy_red[i] = red[i];
          dummy_green[i] = green[i];
          dummy_blue[i] = blue[i];
        }
        red[0] = dummy_red[11];
        green[0] = dummy_green[11];
        blue[0] = dummy_blue[11];
        for(i=1; i<MAXPIXELS; i++){
          red[i] = dummy_red[i-1];
          green[i] = dummy_green[i-1];
          blue[i] = dummy_blue[i-1];
        }
        red_dif[0] = float(red[0] - red[11])/256;
        green_dif[0] = float(green[0] - green[11])/256;
        blue_dif[0] = float(blue[0] - blue[11])/256;
        for(i=1; i<MAXPIXELS; i++){
          red_dif[i] = float(red[i] - red[i-1])/256;
          green_dif[i] = float(green[i] - green[i-1])/256;
          blue_dif[i] = float(blue[i] - blue[i-1])/256;
        }
        cnt = 0;
      }
      RotationTime = millis();
    }
  }
  yield();
}
//***************ブラウザへのカラーボタンValue値送信関数*******************
void WebSocket_Browser_ColButton_Value_Send(String ID, int16_t Max_num, uint8_t* rv, uint8_t* gv, uint8_t* bv){
  char rc[3], gc[3], bc[3], id_num[3];
  String c_code, ID_str;
  
  for(int i=0; i<Max_num; i++){
    //数値を16進数文字列に変換
    sprintf(rc, "%02x", rv[i]);
    sprintf(gc, "%02x", gv[i]);
    sprintf(bc, "%02x", bv[i]);
    //id番号は10進数文字列に変換
    sprintf(id_num, "%02d", i);
    
    c_code = '#' + String(rc) + String(gc) + String(bc); //HTMLカラーコード文字列を作る
    ID_str = ID + String(id_num);
    //ブラウザへWebSocket通信で文字列を送信
    ews.EWS_ESP8266_Str_SEND(c_code, ID_str); //EasyWebSocketライブラリ。ブラウザへ文字列送信
  }
}

【解説】

EasyWebSocket は過去の記事で解説しておりますので、所々説明を省かせていただきます。

●12-13行:
ご自分のルーターのSSIDとパスワードに書き換えてください。

●15-16行:
SPIFFSでアップロードしたHTMLヘッダ分割ファイルを定義しています。
必ず先頭にスラッシュを置くことです。

●19行:
NeoPixelとシリアル通信するピン番号と、NeoPixel LED素子の数を定義します。

●21行:
Adafruit NeoPixel ライブラリのクラス定義

●24行:
ESP8266ライブラリでローカルIPアドレスを自動取得したものを格納

●38-45行:
NeoPixel のLED の3原色をそれぞれ、256段階の数値で格納しておく変数を定義。
12個の配列にしておきます。
グローバル変数領域にしておくことで、ローテーションをストップしたりしてもメモリから呼び出すことができます。

●48-50行:
隣のLEDの明るさの差を格納しておきますが、float型にしておきます。
なぜかというと、フェードイン、フェードアウトするときに256段階にしたいので、256で割って、四捨五入した段階ずつフェードインしたいのです。
そのため、後述するround関数を使うので、それにはfloat型でないと正常に動作しないという理由があるからです。

●63-102行:
115行目のEasyWebSocketライブラリ関数でスマホブラウザへ送信するHTMLのbody要素内をString変数に格納しておきます。
Canvas_Slider 関数は吐き出す文字列が多い為、一つのString変数に2つまでしか入れることができないことに注意してください。
Canvas_Slider はマウスでは操作できません。
マウスで操作したい場合は
EWS_Mouse_Slider_T などの関数を使用してください。

●85-96行:
EasyWebSocket で今回新たに追加した関数です。
HTML5 の Color Picker 文字列を吐き出します。
最初に述べた、

<input type="color" value="#FF1234" >

というような文字列を吐き出します。

Color_Picker(  相対座標X,  相対座標Y, “カラーコード”, “ID文字列”);

相対座標は、カラーピッカーを置いた行からの座標になります。画面の左上からではありません。
座標で決定するので、テキストにダブって表示される場合があります。
テキストとうまく合わせて、97行のように適度に改行を入れてください。
ID文字列とスマホブラウザのカラーピッカーボタンのIDと連動するようになってます。
261-278行の関数でスマホへ送信されたカラーピッカーのValue値が更新されて色が変わるようになってます。
LED素子の位置と、スマホブラウザの表示位置が異なるために、番号順とはいきませんでした。
これは各自の環境に合わせて調節してみてください。
iOSの場合は、後述しているようにカラーピッカーの表示が大きいので、別途位置調節してください。

●106行:
これは、ESP8266ボードライブラリで、ESPr Developer ( ESP-WROOM-02, ESP8266 ) のローカルIPアドレスを自動取得しています。

●115行:
EasyWebSocket_SPIFFSライブラリで1.48から追加したものです。
ブラウザからGETリクエストが発生したら、HTMLヘッダ分割ファイルと、ローカルIPアドレスとbody要素をマージ(合体)して、スマホのブラウザへ送信して、WebSocket通信を確立(ハンドシェイク)させています。

●120行:
スマホブラウザからWebSocket通信で送られてきたテキストデータを受信して、ret_strへ格納します。
この関数はbeta ver 1.48 でブラウザからのClosing メッセージを表示できるようにしてます。

●122-194行:
スマホから明るさ調節スライダーを操作すると
109|Brightness;
という感じでテキストデータが送られてきます。
最初の3文字は0-255段階の数値で、その文字列を数値に変えて setBrightness 関数に代入してます。
4バイト目(5文字目)の ‘B’ という文字をswich関数で分類してます。
ローテーションスピードや、ストップ、オンオフボタンも同じ要領で分類してます。
カラーピッカーは
100|LED09,000,255,255;
のような文字列で送られてきます。
4バイト目の ‘L’ という文字でLED のカラーピッカーと判別して、その後の2桁の数値がLED番号、その後の3桁の数値がそれぞれRed, Green, Blue という並びです。
Char型文字列を数値化するには、関数を使うよりも、それぞれの桁から0x30を引いた方が計算が速いと思います。
163-171行では、隣のLEDの明るさとの差を取り、256段階でフェードイン、アウトさせたい為に、256で割る必要があります。
少数以下は四捨五入する round 関数を使いますが、その引数はfloat型にしないと正しく計算されませんのでご注意ください。
これは、Twitter のまりすさんから教わりました。
まりすさん、ありがとうございます。m(_ _)m

●152-156行:
Rotation OFF ボタンが押されたら、261-278行の関数を呼び出して、今点灯しているLED のRed値、Green値、Blue値をスマホブラウザへ送信します。

●196-257行:
ローテーションONボタンが押されたら、256段階で隣のLEDとフェードインアウトしていきます。
cnt が256に達したら、LED の色を隣にコピーさせてます。

●261-278行:
今回のプログラムの目玉は、私的にはここがポイントですね。
現在点灯しているNeoPixel LED のRed値、Green値、Blue値をHTML形式のカラーコード文字列に変換してから、LED番号もマージしてスマホに送ります。
すると、HTMLヘッダのJavaScript で分類して、カラーピッカーのvalue値が変更され、ボタンの色が変わります。

9.コンパイル書き込み、実行

では、Arduino IDEでコンパイル書き込みしてください。

書込み終了したら、即シリアルモニターを115200bpsで起動してください。
すると、ルーター(アクセスポイント)と接続できれば、そこにローカルIPアドレスが表示されると思います。

次に、スマホをWi-Fi接続して、Google Chrome などのブラウザを起動して、URLアドレス入力欄にそのローカルIPアドレスを入力すると動画のようにWebSocket接続されると思います。

接続されたら、以下のような画面になります。

ColorPicker06

明るさ調節やスピード調節スライダーは、ESP8266 へ連続してデータが送信されるので、処理が追い付かず、たまにフリーズします。
それを防ぐために、Transfer Rate で送る秒数をミリセコンド単位で調節してください。

カラーピッカーはAndroid では下図の様になります。
ColorPicker01

詳細表示をタッチすると下図の様になります。
ColorPicker02

結構オモシロイように調節できますね。
iOS ではこんな感じになってしまいます。
ColorPicker04

これはiOS 10.2 Safari ですが、テキスト数値ですね。
でも、value値はちゃんと反映されてます。
色を変えるには数値を入力しなければなりません。
iOS ではまだまだ対応が遅れているという状況でしょうか・・・。

Windows 10 ではこのようになります。
ColorPicker03

これは情報量が多くて、とても使い易いです。
ちゃんとカラーコードも表示されてますし、Goodです。

10.まとめ

いかがでしょうか。
ちゃんと動作しましたでしょうか。
もし、不具合等あったらコメント等でご連絡いただけると幸いです。

これで、このオブジェでクリスマスや正月など、雰囲気に合わせてリアルタイムで色を変えることができました。
しかもスマホでできるというのがイイですね。
これからもっといろいろアイデアが広がりそうです。

しかし、この記事を書くのにエライ労力がかかります。
とても疲れてしまいました。

ではまた・・・。

スポンサーリンク

Amazon.co.jp広告







投稿者:

mgo-tec

Arduino, ESP8266, ESP-WROOM-02 等を使って、主にスマホと連携した電子工作やプログラミング記事を書いてます。ライブラリも作ったりしてます。趣味、独学でやってます。

「オブジェの LED カラー を スマホ ブラウザ で WiFi リアルタイム コントロール してみた」への2件のフィードバック

  1. Hi,

    Do you do custom work?

    Really like the yahoo news wroom oled

    Do you sell them? Do you have them in English.

    I need about 100 boards with color OLED

    Thank you

    John

    1. Thank you very much for your very grateful comment.

      Unfortunately, I do not sell.
      About Yahoo news OLED, English version is also under consideration.
      If it can be done, I will inform you in this comment section.
      Code will be made public.
      Please wait for a while, I think that it will take some time.

コメントを残す

メールアドレスが公開されることはありません。


*