フォト
2023年3月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
無料ブログはココログ

« windows 10でwhoamiコマンドの動きがなんか違う? | トップページ | 4連8x8ドットLEDマトリックスを試してみる »

2016年7月 2日 (土)

ESP-WROOM-02を始めました(4) WiFi経由でLEDを制御

ESP-WROOM-02GPIOまわりの雰囲気が分かったので、
本来の目的のIoTをボチボチとやり始めました。

Dscn5367

まずは、Arduino IDEのサンプルソースのSDWebserverを修正して
簡単なLED制御プログラムを作って見ました。

スマートフォンにてESP-WROOM-02にて稼働するWebサーバーに接続して
LEDを制御しています。

動作の様子

動作としては単純なのですが、ESP-WROOM-02が具体的に何をやっていると言うと
  1)WiFiアクセスポイント 機能の提供
  2)接続したスマートフォンにIPアドレスの配布(DHCP)
  3)Webサーバー
  4)WebコンテンツをSDカードから配信
  5)URL名前解決(DNSサーバー)
  6)LEDの制御

てな感じです。

ESP-WROOM-02がWiFiアクセスポイントになっているので、既存ネットワークが無くても
スマートフォンから接続することが出来ます。

動画見ると分かりますが、表示レスポンス等、Webサーバーとしてはさすがに遅いです。
ですので、ボタン操作によるLED制御は、非同期通信を使ってページ更新が発生しない
ようにしました。

結線

05ピン    LEDのアノードへ接続
13ピン    microSDカードモジュールのMOISに接続
12ピン    microSDカードモジュールのMISOに接続
14ピン    microSDカードモジュールのCLKに接続
15ピン    microSDカードモジュールのCSに接続

microSDカードの接続・使い方はスイッチサイエンスさんの記事
   ESP-WROOM-02を使ったWi-Fi機能付き温度ロガーを作る(1)
が参考になると思います。

スケッチ
ダウンロード SDWebServerEx.zip (64.5K)

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <SPI.h>
#include <SD.h>

#define DBG_OUTPUT_PORT Serial
#define LED_PIN 5

const char* ssid = "esp8266";
const char* password = "xxxxxxx";
const char* host = "sd.local";
const byte DNS_PORT = 53;

IPAddress apIP(192, 168, 0, 1);
DNSServer dnsServer;
ESP8266WebServer server(80);

static bool hasSD = false;

void returnOK() {
  server.send(200, "text/plain", "");
}

void returnFail(String msg) {
  server.send(500, "text/plain", msg + "\r\n");
}

bool loadFromSdCard(String path){
  String dataType = "text/plain";
  if(path.endsWith("/")) path += "index.htm";

  if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if(path.endsWith(".htm")) dataType = "text/html";
  else if(path.endsWith(".css")) dataType = "text/css";
  else if(path.endsWith(".js")) dataType = "application/javascript";
  else if(path.endsWith(".png")) dataType = "image/png";
  else if(path.endsWith(".gif")) dataType = "image/gif";
  else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  else if(path.endsWith(".ico")) dataType = "image/x-icon";
  else if(path.endsWith(".xml")) dataType = "text/xml";
  else if(path.endsWith(".pdf")) dataType = "application/pdf";
  else if(path.endsWith(".zip")) dataType = "application/zip";

  File dataFile = SD.open(path.c_str());
  if(dataFile.isDirectory()){
    path += "/index.htm";
    dataType = "text/html";
    dataFile = SD.open(path.c_str());
  }

  if (!dataFile)
    return false;

  if (server.hasArg("download")) dataType = "application/octet-stream";

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    DBG_OUTPUT_PORT.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}

void handleNotFound(){
  if(hasSD && loadFromSdCard(server.uri())) return;
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  DBG_OUTPUT_PORT.print(message);
}

// LEDの制御
void handleLED() {
  if (!server.hasArg("LED")) {
    String msg = "Command Error\n";
    returnFail(msg);
    return;
  }

  String cmd = server.arg("LED");
  if (cmd == "on") {
    digitalWrite(LED_PIN, HIGH);
    DBG_OUTPUT_PORT.println("LED ON");
  }    
  if (cmd == "off") {
    digitalWrite(LED_PIN, LOW);
    DBG_OUTPUT_PORT.println("LED OFF");
  }
  returnOK();
}

void setup(void){
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);  
  DBG_OUTPUT_PORT.begin(115200);
  DBG_OUTPUT_PORT.setDebugOutput(true);
  DBG_OUTPUT_PORT.print("\n");

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssid, password);

  dnsServer.setTTL(300);
  dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
  dnsServer.start(DNS_PORT, host, apIP);

  server.onNotFound(handleNotFound);
  server.on("/do",HTTP_GET, handleLED);
  
  server.begin();
  DBG_OUTPUT_PORT.println("HTTP server started");

  if (SD.begin(SS)){
     DBG_OUTPUT_PORT.println("SD Card initialized.");
     hasSD = true;
  }
}

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


Webページ
とりあえず、トップ画面のみ掲載します。ファイルはSDカードに入れています。
SDカードライブラリの制約でファイル名は8.3文字となります。

スマートフォンに表示されているページや画像はSDカードに入れています。
ページは2ページ構成です。

簡単な説明
スマートフォンからは、まずssidがesp8266のアクセスポイントに接続します。
このあたりは、ESP-WROOM-02

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP(ssid, password);
でやってます。

次にスマートフォンからブラウザにて、URL http://led.local  にアクセスして
LED制御画面を(index.htm)を表示します。

ESP-WROOM-02
でこのアクセスによるコンテンツ画面配信のための、
名前解決は DNSServer dnsServer にて生成したDNSサーバーがやってくれています。

コンテンツの配信は下記のコードでやっています。まずはハンドラの設定は
  server.onNotFound(handleNotFound);
  server.on("/do",HTTP_GET, handleLED);
です。 LEDを制御するためのURL(GET)は、スマートフォンから
   http://led.local/do?LED=on    でLED点灯
   http://led.local/do?LED=off   でLED消灯
のアクセスでやっています。

このled.local/do のURLでアクセスされた場合にLEDの制御を行うため
  server.on("/do",HTTP_GET, handleLED);
と記述して、処理を行う関数 habdleLED() を指定しています。またdo?LED=on 形式で
スマートフォンから変数LEDの値を渡す方式(GET)を指定するためにHTTP_GET
指定しています。

led.local/do 以外のURLでアクセスされた場合は、
  server.onNotFound(handleNotFound);
と記述して、関数 handleNotFound() を呼び出すように指定しています。

handleNotFound()では、loadFromSdCard(String path) を呼び出して
URLで指定したファイルがあればそのファイルをSDカードから
読みだして、配信を行っています("/" の場合は"/index.htm"ファイルを配信)。

今回はサンプルを参照してサクッと作成しましたが、
Webサーバーを操るにあたり、HTTPのプロトコルをちょっと突っ込んで学ばないと
いけないようです。

ただし、ライブラリが充実しており、ちょっとしたプログラムも意外と簡単に作れることが分かりました。

« windows 10でwhoamiコマンドの動きがなんか違う? | トップページ | 4連8x8ドットLEDマトリックスを試してみる »

ESP32・ESP8226」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック


この記事へのトラックバック一覧です: ESP-WROOM-02を始めました(4) WiFi経由でLEDを制御:

« windows 10でwhoamiコマンドの動きがなんか違う? | トップページ | 4連8x8ドットLEDマトリックスを試してみる »