ArduinoでWebServerを使うためのメモ。
◆スケッチ
ファイル/スケッチ例/Ethernet/WebServer
から改変
◆MACアドレス
お試しで遊ぶのなら、まあ、適当に。
◆IPアドレス
スケッチのままだと、IPアドレス指定になっている。
お試しだったら、DHCPから取得の方がはるかに使いやすいような、、、。
1 |
Ethernet.begin(mac, ip); |
を
1 |
Ethernet.begin(mac); |
とすると、DHCPからの取得になる。
◆シリアルモニタ
シリアル通信のデータ転送レートは230400とかにしてした方が使いやすい。
次の表は、「ファイル/スケッチ例/Ethernet/WebServer」からほとんどいじらない状態での、転送レートによる読み込み時間の違い。
シリアル通信のデータ転送レートbps(baud) | PCのブラウザで読み込みまでの時間(ms) |
---|---|
9600 | 478 |
19200 | 249 |
38400 | 133 |
57600 | 93 |
74880 | 78 |
115200 | 56 |
230400 | 52 |
250000 | 53 |
500000 | 52 |
1000000 | 52 |
2000000 | 52 |
230400以降は変わらない。環境によって違うと思うので参考程度にどうぞ。
1 |
Serial.begin(9600); |
を
1 |
Serial.begin(230400); |
とする。
◆ヘッダー
APIっぽくしようとURLによって処理分けをする場合、ヘッダーをそのままメモリ上に置いてしまうと、あふれることもあり処理が不安定になる。
なので、リクエストの1行目のメソッド、パス、プロトコル(GET /hoge/ HTTP/1.1)の部分のみを取得して処理をしたほうが良い。
「ファイル/スケッチ例/Ethernet/WebServer」を元にヘッダーの処理を入れてみた。
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 |
/* Web Server A simple web server that shows the value of the analog input pins. using an Arduino Wiznet Ethernet shield. Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 * Analog inputs attached to pins A0 through A5 (optional) created 18 Dec 2009 by David A. Mellis modified 9 Apr 2012 by Tom Igoe modified 02 Sept 2015 by Arturo Guadalupi */ #include <SPI.h> //#include <Ethernet.h> #include <UIPEthernet.h> // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 1, 177); // Initialize the Ethernet server library // with the IP address and port you want to use // (port 80 is default for HTTP): EthernetServer server(80); String pathname = ""; String query = ""; void setup() { // You can use Ethernet.init(pin) to configure the CS pin //Ethernet.init(10); // Most Arduino shields //Ethernet.init(5); // MKR ETH shield //Ethernet.init(0); // Teensy 2.0 //Ethernet.init(20); // Teensy++ 2.0 //Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet //Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet // Open serial communications and wait for port to open: Serial.begin(230400); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("Ethernet WebServer Example"); // start the Ethernet connection and the server: Ethernet.begin(mac); // Check for Ethernet hardware present if (Ethernet.hardwareStatus() == EthernetNoHardware) { Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); while (true) { delay(1); // do nothing, no point running without Ethernet hardware } } if (Ethernet.linkStatus() == LinkOFF) { Serial.println("Ethernet cable is not connected."); } // start the server server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP()); } // クエリーに対応する値があれば返す String getQuery(String command) { if(query.indexOf(command + "=") > -1){ int num = query.indexOf(command + "="); int start = num + command.length() + 1; int end = query.indexOf("&", start); if(end == -1){ end = query.length(); } return query.substring(start, end); } return ""; } void loop() { // listen for incoming clients EthernetClient client = server.available(); if (client) { Serial.println("new client"); // an http request ends with a blank line boolean currentLineIsBlank = true; boolean isGETLine = true; String header = ""; String headerGET = ""; while (client.connected()) { if (client.available()) { char c = client.read(); //Serial.write(c); // 最初の\nまでをヘッダーとして取得 if(isGETLine){ if(c == '\n'){ isGETLine = false; Serial.println(header); }else{ header += String(c); } } // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { headerGET = header.substring(header.indexOf(" ")+1, header.lastIndexOf(" ")); // favicon.ico対策 if(headerGET == "/favicon.ico"){ client.println("HTTP/1.1 204 OK"); client.println("Connection: close"); client.println(); break; } // ?より前までをパスとして取得 pathname = headerGET.substring(0, headerGET.indexOf("?")); // ?があれば、クエリーとして取得 query = headerGET.indexOf("?") > -1?headerGET.substring(headerGET.indexOf("?")+1):""; Serial.println("pathname=" + pathname + ", query=" + query); // send a standard http response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println("Refresh: 5"); // refresh the page automatically every 5 sec client.println(); client.println("<!DOCTYPE HTML>"); client.println("<html>"); // output the value of each analog input pin for (int analogChannel = 0; analogChannel < 6; analogChannel++) { int sensorReading = analogRead(analogChannel); client.print("analog input "); client.print(analogChannel); client.print(" is "); client.print(sensorReading); client.println("<br />"); } // ディレクトリやクエリーで分けてみたらいかが?提案用 client.println("<a href='../abc/?a=123&b=456'>../abc/?a=123&b=456</a>"); client.println("<br />"); // API ぽく使いたい時はディレクトリ分けしたら良いかも if(pathname == "/abc/"){ String a = getQuery("a"); String b = getQuery("b"); if(a != "" && b != ""){ client.println("a=" + a + ", b=" + b); Serial.println("a=" + a + ", b=" + b); } } client.println("<br />"); client.println("pathname:" + pathname + ", query:" + query); client.println("</html>"); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); Serial.println("client disconnected"); } } |
恐らく、もっと良い方法があるんだとは思うんだけど、、、
このあたりのメモリのやりくりは、21世紀にPC/Webからプログラムを始めて、いわゆる富豪的プログラミングを是としてきた自分としては、なかなか慣れない世界だ。