目的:
ESP32基板のLED(IO2) を PWM で調光し、明るさを WEBのスライダーで調整する。
方法:
スライダーは form の <input> で type を 'range' にする。
スライダーの操作時にリアルタイムで値をESP32基板に送信するには、スライダーの値が変わる度に JavaScript で XMLHttpRequest を使用して値を送信する。(非同期通信)
また、ESP32で受信した値をブラウザに送り、ブラウザの表示を更新する様にする。
2019/06/26追加
XHR を多重で発行すると通信がハングアップする事がある様子。
修正 内容は、こちらを参照。
Arduino core for the ESP32 の Ver 1.0.2 の問題と思われる。
→ 本問題は、
Ver.1.0.3 以降では問題無い。
例:
UPボタンで値を +1 し、OFF ボタンで値を 0 にする。
テキストボックスに直接値を設定することも可能。
以下、「LED調光_明るさをテキストで設定」からの主な変更箇所をハイライト。
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | /* * WiFi LED ON/OFF TEST * PWM Control * slider control */ #include <WiFi.h> //#define DEBUG const char* ssid = "hogehoge"; const char* password = "hogehogepaswd"; IPAddress ip(192, 168, 1, 32); // for fixed IP Address IPAddress gateway(192,168, 1, 1); // IPAddress subnet(255, 255, 255, 0); // IPAddress DNS(192, 168, 1, 90); // WiFiServer server(80); byte led_brightness = 0 ; void setup() { Serial.begin(115200); pinMode(2, OUTPUT); // set the LED pin mode WiFi.config(ip, gateway, subnet, DNS); // Set fixed IP address delay(10); // We start by connecting to a WiFi network ----------------------------- 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.print("IP address: "); Serial.println(WiFi.localIP()); server.begin(); // for LED PWM Control --------------------------------------------------- sigmaDeltaSetup(0, 312500); // setup channel 0 with frequency 312500 Hz sigmaDeltaAttachPin(2,0); // attach pin 2 to channel 0 sigmaDeltaWrite(0, 0); // initialize channel 0 to off } void loop(){ WiFiClient client = server.available(); // listen for incoming clients int pos ; int val ; int xhr ; String cmd = "" ; if (client) { // if you get a client, # ifdef DEBUG Serial.println("***** Client access start *****"); // print a message out the serial port #endif xhr = 0 ; while (client.connected()) { // loop while the client's connected if (client.available()) { // if there's bytes to read from the client, String line = client.readStringUntil('\n'); // Get Line data until '\n' # ifdef DEBUG Serial.println(line); #endif if ((pos= line.indexOf("GET /?slid")) != -1) { pos += 11 ; while((line.charAt(pos) >='0') & (line.charAt(pos) <='9')) { cmd += line.charAt(pos++) ; } val = cmd.toInt() ; if (val>256) val = 255 ; led_brightness = (byte)val ; xhr=1; # ifdef DEBUG Serial.print("led_brightness : "); Serial.println(led_brightness) ; #endif } if ((pos= line.indexOf("GET /?led_v")) != -1) { pos += 12 ; while((line.charAt(pos) >='0') & (line.charAt(pos) <='9')) { cmd += line.charAt(pos++) ; } val = cmd.toInt() ; if (val>256) val = 255 ; led_brightness = (byte)val ; # ifdef DEBUG Serial.print("led_brightness : "); Serial.println(led_brightness) ; #endif } if ((pos=line.indexOf("GET /?on")) != -1) { // Client request was "GET /?on" led_brightness += 1 ; # ifdef DEBUG Serial.print("led_brightness : "); Serial.println(led_brightness); #endif } if ((pos=line.indexOf("GET /?off")) != -1) { // Client request was "GET /?off" led_brightness = 0 ; # ifdef DEBUG Serial.print("led_brightness : "); Serial.println(led_brightness); #endif } sigmaDeltaWrite(0, led_brightness) ; // set PWM value to channel#0 if (line.length() == 1 && line[0] == '\r'){ // end of HTTP request if (xhr == 0) send_response(client) ; // send response to client else send_response2(client) ; // send response to client break; // break while loop } } } delay(1); // give the web browser time to receive the data // close the connection: client.stop(); # ifdef DEBUG Serial.println("Client Disconnected."); Serial.println("--------------------------------------------------"); #endif } } // ------------------------------------------------------------------ void send_response(WiFiClient client) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); // the content of the HTTP response follows the header: client.println("<!DOCTYPE html><html lang='ja'><head><meta charset='UTF-8'>" ) ; client.println("<style>input.button {margin:8px;width:100px;}" ) ; client.println(" input.button2 {margin-left:8px; width:40px;}" ) ; client.println(" input.text {margin-left:8px; width:25px;}" ) ; client.println(" input.slid {width:230px;}" ) ; client.println(" div {font-size:16pt;text-align:center;width:250px;border:solid 4px #93ff93;} " ) ; client.println(" </style>" ) ; client.println("<title>Color LED Controller</title></head>" ) ; client.println("" ) ; client.println("<body>" ) ; client.println("<div><p>LED ON/OFF</p>" ) ; client.println(" <form method='get' style='text-align:left' > " ) ; client.println(" <span style='padding-left:15pt; font-size:8pt ;text-align:left'> LED brightness (0-255)</span> " ) ; client.println(" <input class='text' type='text' name='led_v' id='led_v' value=" ) ; client.println(led_brightness ) ; client.println(" >" ) ; client.println(" <input class='button2' type='submit' name='set' value='SET'>" ) ; client.println(" </form> " ) ; client.println("" ) ; client.println(" <form name='slidform' method='get' style='text-align:left'> " ) ; client.print(" <input class='slid' type='range' name='led_s' value=" ) ; client.print(led_brightness ) ; client.println(" min='80' max='255' step='1' onchange='setval(this.value)' oninput='setval(this.value)' >" ) ; client.println(" </form> " ) ; client.println("" ) ; client.println(" <form method='get'>" ) ; client.println(" <input class='button' type='submit' name='on' value='ON'><input class='button' type='submit' name='off' value='OFF'><br>" ) ; client.println(" </form>" ) ; client.println("" ) ; client.println(" </div>" ) ; client.println("" ) ; client.println("" ) ; client.println("<script>" ) ; client.println("function setval(ledval){" ) ; client.println(" var xhr = new XMLHttpRequest();" ) ; client.println(" xhr.open('get', '?slid='+ledval );" ) ; client.println(" xhr.timeout = 1000 ;" ) ; client.println(" xhr.setRequestHeader('Cache-Control', 'no-cache');" ) ; client.println(" xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');" ) ; client.println(" xhr.responseType = 'document' ;" ) ; client.println("" ) ; client.println(" xhr.onreadystatechange = function() {" ) ; client.println(" if( (xhr.readyState == 4) && (xhr.status == 200) ) {" ) ; client.println(" document.getElementById('led_v').value = xhr.response.getElementById('output1').innerHTML;" ) ; client.println(" }" ) ; client.println(" }" ) ; client.println(" xhr.ontimeout = function(e) {" ) ; client.println(" xhr.abort() ;" ) ; client.println(" }" ) ; client.println(" xhr.send();" ) ; client.println("}" ) ; client.println("" ) ; client.println("</script>" ) ; client.println("</body>" ) ; client.println("</html>" ) ; client.println("") ; Serial.println( " --- send responce --- "); } void send_response2(WiFiClient client) { client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); client.println("<!DOCTYPE html><html lang='ja'>" ) ; client.println(" <head> <title>Color LED Controller</title></head>") ; client.println("<body>") ; client.print("<output id='output1'>") ; client.print(led_brightness ) ; client.println(" </output> ") ; client.println("</body>") ; client.println("</html>") ; # ifdef DEBUG Serial.println( " --- send responce2 --- "); #endif } |
以下、XMLHttpRequest を使用して非同期通信する場合の覚書など。
--- ESP32 の処理 ( Loop 処理 等 )---
( 行# 64,66,71,73,96,99,103,106,110,113,129,132 )
スライダー操作時のタイムラグをなるべく小さくするため、デバッグ用の表示はデバッグ時のみにする様、ifdef で制御する。
( 行# 74-87)
XMLHttpRequest での get要求を 受けた場合の処理。送信された値を取得し、XMLHttpRequestでの要求であることを覚えておく。(xhr=1;)
( 行# 118-122)
html全体の送信 又は XMLHttpRequest への応答 を選択する。
--- HTML 送信 ----
( 行# 150)
スライダーの幅を設定。
( 行# 165-169)
スライダーを設置。
値が80未満の場合は LED がほとんど光らなかったため、スライダーの値は 80~255 とした。
スライダーの値が変化した時(onchange, oninput) 、javascript の setval を実行。(スライダーの値を引数とする。setval で XMLHttpRequest を使用して値を送信処理する)。
IE と その他で onchange, oninput の動作が異なるため、両方とも setval を実行する様にする。
( 行# 179-199)
非同期通信用の javascript。 主に以下の順に処理を行う。
var xhr = new XMLHttpRequest() ; で新規にオブジェクトを生成。
xhr.open('get', '?slid='+ledval );" ) ; で HTTPメソッド、アクセス先URLを指定。
xhr.onreadystatechange = function() { ...} で応答が返った時の処理を登録。
xhr.send() ; で 処理を実行 ( リクエストを送信 ) する。
尚、
xhr.open の 第2引数で リクエストを送信する url を指定するが、ここに GET で送信するデータ(?slid=<スライダの値>) を入れる。(ESP32基板では ?slid の受信で XMRHttpRequest を受け取ったと判定する。)
非同期で複数の値を通信した場合、応答が遅れて受信する順序が入れ替わる場合があったため、一定時間以上(ここでは 1秒)はタイムアウトとする様に、xhr.timeout を設定。timeout 時は 処理をアボートする様、xhr.ontimeout に設定する。
(IE の場合 ?) ブラウザのキャッシュが効いて ESP32 にデータを送信しなくなる場合があったため、キャッシュを無効にする様に設定。
xhr.setRequestHeader('Cache-Control', 'no-cache');" ) ;
xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');" ) ;
XMRHttpRequest の 応答を HTMLで行い、パースするため、 responseType を'document' に設定する。
応答が返った時の処理内容 :
readystate=4 かつ status = 200 の時、
応答の 'output1' の値を html の led_v (テキストボックス) の値に代入する。
--- XMRHttpRequest への応答 ----
( 行# 206-221)
XMRHttpRequest(?slid) を受け取った時の応答
html で id = 'output1' として led_brightness の値を 送信する。
本例では、XMRHttpRequest の応答として HTML で 応答したが、JSON で応答する様にした方が良いかもしれない。
0 件のコメント:
コメントを投稿