WROOM-02動作のまねごと part 5 [Arduino]
WROOM-02ネタ
PC組み立てにかまけて,ほったらかしでした。
今回は,ソースです。
2015/10/15 ソース一部修正。
とは言っても,TFT表示の見直しは,やっていません。
中身は,使ったライブラリのサンプルをちょっとだけ手直しして,くっつけただけです。
動かすには,SDカードのルートにSDWebServer(/index.htm, /edit/index.htm)のファイルの他,settings.txtを置きます。
settings.txt
以下がソース。
ESP03.ino
な,感じ。
PC組み立てにかまけて,ほったらかしでした。
今回は,ソースです。
2015/10/15 ソース一部修正。
とは言っても,TFT表示の見直しは,やっていません。
中身は,使ったライブラリのサンプルをちょっとだけ手直しして,くっつけただけです。
動かすには,SDカードのルートにSDWebServer(/index.htm, /edit/index.htm)のファイルの他,settings.txtを置きます。
settings.txt
// Wifi Settings ssid=hogehoge pw=hogehogehoge mdns=esp826603 // for NTP ntp_server=ntp.nict.jp timezoneoffset=9 ntp_interval=180 // for BME280 sealevel=75 dispinterval=5 loginterval=1
以下がソース。
ESP03.ino
/* ESP03 (20151005) */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> // for NTP #include <Adafruit_GFX.h> // Core graphics library #include <Adafruit_ST7735.h> // Hardware-specific library #include <SPI.h> #include <SD.h> #include <Wire.h> // http://blog.eldhrimnir.com/wordpress/?p=864 Arduino用RTCライブラリ(DS1307/RTC8564) #include <RTClib_2.h> #include <BME280_MOD-1022.h> // I2C温湿度・気圧センサ #include <Ticker.h> // ESP8266 Timer Library ? // SainSmart 1.8 TFT Display #define TFT_CS 15 // pin6 : Low(10k) #define TFT_RST 0 // not use Reset #define TFT_DC 0 // pin8 : Boot Mode Select(Low or High) Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); // SD Card #define SD_CS 2 // IO2 is High(10k) // set up variables using the SD utility library functions: Sd2Card card; SdVolume volume; SdFile root; File uploadFile; //SDWebServer用 static bool hasSD = false; // SDカードの有無Flag // Wire(I2C) #define I2C_SDA 4 // pin 10 #define I2C_SCL 5 // pin 14 // BME280 温湿度・気圧センサー #define BME280_ADDR 0x76 // I2C Address (select Pin5 0x76(GND) or 0x77(VDD) // RTC8564-BN RTC byte RtcADR = 0XA2 >> 1; // RTC8564 I2Cアドレス // その他 #define DBG_PORT Serial #define settings "settings.txt" //settings.txt #define SECS_PER_HOUR (3600UL) // Time.hから #define SECS_PER_MIN (60UL) // settings.txt読み出し結果格納 char* ssid = "ssid\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; // 34文字分 char* pw = "pass\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; // 24文字分 char* host = "host\0\0\0\0\0\0\0\0\0\0\0\0\0"; // 17文字分 char* ntpServerName = "ntp\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; // 33文字分 long LocalTimeOffset; // int? int ntpinterval; int sealevel; int dispinterval; int loginterval; /* 内部フラグ */ bool flagdbg = true; // 表示ディレー bool flagntp = false; // ntp 成功(Ture)/失敗(False) // for NTP unsigned int localPort = 2390; // local port to listen for UDP packets IPAddress timeServerIP; // NTP server address const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets DateTime LastUpdate; // last update date WiFiUDP udp; // A UDP instance to let us send and receive packets over UDP // for RTC RTC_RTC8564 Rtc; //RTC-8564 JE/NB I2C Real-Time Clock // WebServer ESP8266WebServer server(80); // 割り込み Ticker TickTack; // 時間書き換え Ticker tmTemp0; //温湿度計測(表示) Ticker tmTemp1; //温湿度計測(SD書き出し) void setup() { Serial.begin(115200); DBG_PORT.print("\n"); tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip, black tab tft.setRotation(3); // 270°回転 tftdrawtext("Startup....", ST7735_WHITE, 1); Wire.begin(I2C_SDA, I2C_SCL); delay(40); // I2c pin (SDA, SCL) Rtc.begin(); delay(40); // RTCスタート // SD開始 if (SD.begin(SD_CS)) { tft.println("SD Card initialized."); hasSD = true; // SDカード有 } else { tft.println("SD Card initialize Fail."); hasSD = false; // SDカード無 exit; } if (flagdbg) delay(2000); // 表示Delay(なくてもOK) // ファイルからネタ読み出し tftdrawtext("Read SD Card....", ST7735_WHITE, 1); String sssid, spw, shost, sntpsv; File mySettings; mySettings = SD.open(settings); if (mySettings) { tft.print(settings); tft.println(":"); // read from the file until there's nothing else in it: String ln; while (mySettings.available()) { // ネタ取り込み char wd = mySettings.read(); // btye→char //tft.print(wd); if (wd == '\n') { // 1行出来た String idx = ln.substring(0, ln.indexOf('=')); //+ '\0'; // 前半分 String src = ln.substring(ln.indexOf('=') +1); //+ '\0'; // 後ろ半分 char ret[src.length() + 1]; if (idx.equalsIgnoreCase("ssid")) sssid = src; if (idx.equalsIgnoreCase("pw")) spw = src; if (idx.equalsIgnoreCase("mdns")) shost = src; if (idx.equalsIgnoreCase("ntp_server")) sntpsv= src; if (idx.equalsIgnoreCase("timezoneoffset")) LocalTimeOffset = src.toInt(); if (idx.equalsIgnoreCase("ntp_interval")) ntpinterval = src.toInt(); if (idx.equalsIgnoreCase("sealevel")) sealevel = src.toInt(); if (idx.equalsIgnoreCase("dispinterval")) dispinterval = src.toInt(); if (idx.equalsIgnoreCase("loginterval")) loginterval = src.toInt(); ln = ""; wd = '\0'; } else { ln += wd; } } // close the file: mySettings.close(); } else { // if the file didn't open, print an error: tft.print("error: opening "); tft.println(settings); exit; } // String->char 移し替え int ss; ss = sssid.length() + 1; ssid[ss]; sssid.toCharArray(ssid, ss); ss = sssid.length() + 1; pw[ss]; spw.toCharArray(pw, ss); ss = shost.length() + 1; host[ss]; shost.toCharArray(host, ss); ss = sntpsv.length() + 1; ntpServerName[ss]; sntpsv.toCharArray(ntpServerName, ss); // Settings.txt読込み結果 tft.println(""); tft.println("SD Read Result:"); tft.print("ssid:"); tft.println(ssid); tft.print("pw:"); tft.println(pw); tft.print("mdns:"); tft.println(host); tft.print("NTPsv:"); tft.println(ntpServerName); tft.print("TimezoneOffset[h]:"); tft.println(LocalTimeOffset); tft.print("NtpInterval[min]:"); tft.println(ntpinterval); tft.print("sealevel[m]:"); tft.println(sealevel); tft.print("dispinterval[Sec]:"); tft.println(dispinterval); tft.print("loginterval[min]:"); tft.println(loginterval); if (flagdbg) delay(2000); // 表示Delay(なくてもOK) // WiFi接続 tftdrawtext("Connecting Wifi....", ST7735_WHITE, 1); WiFi.begin(ssid, pw); tft.println("Connecting to "); tft.println(ssid); uint8_t i = 0; while (WiFi.status() != WL_CONNECTED && i++ < 20) { //wait 10 seconds delay(500); } if(i == 21){ tft.println("Could not connect to"); tft.println(ssid); while(1) delay(500); } tft.println("Connected! IP address: "); tft.println(WiFi.localIP()); if (MDNS.begin(host)) { MDNS.addService("http", "tcp", 80); tft.println("MDNS responder started"); tft.print("You can now connect to http://"); tft.print(host); tft.println(".local"); } server.on("/list", HTTP_GET, printDirectory); server.on("/edit", HTTP_DELETE, handleDelete); server.on("/edit", HTTP_PUT, handleCreate); server.on("/edit", HTTP_POST, [](){ returnOK(); }); server.onNotFound(handleNotFound); server.onFileUpload(handleFileUpload); server.begin(); tft.println("HTTP server started"); if (flagdbg) delay(2000); // 表示Delay(なくてもOK) // NTPで時刻合わせ tftdrawtext("Time Sync....", ST7735_WHITE, 1); SetTimeByNTP(); if (flagdbg) delay(2000); // 表示Delay(なくてもOK) // タイマー割込み TickTack.attach(1.0, redrowsec); // 時刻再描画 tmTemp0.attach(dispinterval, BME280Meas, false); //温度測定(表示) tmTemp1.attach(loginterval * SECS_PER_MIN, BME280Meas, true); //温度測定(表示) tft.fillScreen(ST7735_BLACK); // TFT画面クリア } void loop() { server.handleClient(); reSetTimeByNTP(); // NTP時計合わせ } /* ----- TFT ------- */ void tftdrawtext(char *text, uint16_t color, uint8_t size) { // 画面初期化+1行目にテキスト表示 tft.fillScreen(ST7735_BLACK); tft.setTextSize(size); tft.setCursor(0, 0); tft.setTextColor(color, ST7735_BLACK); tft.setTextWrap(true); tft.println(text); } void tftdrawComment(char *text, uint16_t color) { // TFTのコメントエリア(一番下の行)へテキスト書き込み // 1.8inch (128x160)用 int row, col; row = 128 / 8; col = 160 / 5; // 横置き //row = 160 / 8; col = 128 / 5; // 縦置き tft.setTextWrap(false); tft.setTextSize(1); tft.fillRect(0, (row - 1) * 8, col * 5, 8, ST7735_BLACK); // 行消去 tft.setCursor(0, (row - 1) * 8); tft.setTextColor(color, ST7735_BLACK); tft.print(text); tft.setTextWrap(true); } /* ----- I2C Display Date & Time ------- */ void redrowsec() { // 時刻再描画 DateTime now = Rtc.now(); tft.setTextColor(ST7735_WHITE, ST7735_BLACK); // 日付 tft.setTextSize(1); tft.setCursor(1 * 5, 0); //tft.print(now.month(), DEC); tft.print("/"); // 月を数字で tft.print(printMonth(now.month())); // 月を英文字で printDigitsS(now.day()); tft.print(" "); // 曜日 tft.setCursor(1 * 5, 1 * 8); tft.print("["); if(now.dayOfWeek()==0) { tft.setTextColor(ST7735_RED, ST7735_BLACK); } else if(now.dayOfWeek()==6) { tft.setTextColor(ST7735_BLUE, ST7735_BLACK); } else { tft.setTextColor(ST7735_WHITE, ST7735_BLACK); } tft.print(printWeekDay(now.dayOfWeek())); tft.setTextColor(ST7735_WHITE, ST7735_BLACK); tft.print("]"); // 時刻 if (! Rtc.isrunning()) { tft.setTextColor(ST7735_RED, ST7735_BLACK); } else if(! flagntp) { tft.setTextColor(ST7735_YELLOW, ST7735_BLACK); } else { tft.setTextColor(ST7735_WHITE, ST7735_BLACK); } tft.setTextSize(2); tft.setCursor(12 * 5, 0); printDigits(now.hour()); tft.print(":"); printDigits(now.minute()); tft.print(":"); printDigits(now.second()); tft.setTextSize(1); // 文字サイズを戻す } void printDigits(int digits){ // 時分秒で一桁の時,頭に0をつけます。 if(digits < 10) tft.print('0'); tft.print(digits); } void printDigitsS(int digits){ // 日で一桁の時,頭にSpaceをつけます。 if(digits < 10) tft.print(' '); tft.print(digits); } String printMonth(int digits){ // 月(数字) -> 文字 String ret="mon "; switch (digits) { case 1: ret="Jan."; break; case 2: ret="Feb."; break; case 3: ret="Mar."; break; case 4: ret="Apr."; break; case 5: ret="May "; break; case 6: ret="June"; break; case 7: ret="July"; break; case 8: ret="Aug."; break; case 9: ret="Sep."; break; case 10: ret="Oct."; break; case 11: ret="Nov."; break; case 12: ret="Dec."; break; default: break; } return ret; } String printWeekDay(int digits) { // 曜日(数字) -> 文字 String ret="wk "; switch (digits) { case 0: ret="Sun."; break; case 1: ret="Mon."; break; case 2: ret="Tue."; break; case 3: ret="Wed."; break; case 4: ret="Thu."; break; case 5: ret="Fri."; break; case 6: ret="Sat."; break; default: break; } return ret; } /* ----- 温湿度測定 ------- */ void BME280Meas(bool mode) { // 温湿度測定 /* int sealevel; // m int dispinterval; // Sec int loginterval; // Min */ float temp, humidity, pressure; // 取得,表示(TFT) /* uint8_t chipID; Serial.println("Welcome to the BME280 MOD-1022 weather multi-sensor test sketch!"); Serial.println("Embedded Adventures (www.embeddedadventures.com)"); chipID = BME280.readChipId(); // find the chip ID out just for fun Serial.print("ChipID = 0x"); Serial.println(chipID, HEX); */ // need to read the NVM compensation parameters BME280.readCompensationParams(); // Example for "indoor navigation" // We'll switch into normal mode for regular automatic samples BME280.writeStandbyTime(tsb_0p5ms); // tsb = 0.5ms BME280.writeFilterCoefficient(fc_16); // IIR Filter coefficient 16 BME280.writeOversamplingPressure(os16x); // pressure x16 BME280.writeOversamplingTemperature(os2x); // temperature x2 BME280.writeOversamplingHumidity(os1x); // humidity x1 BME280.writeMode(smNormal); while (BME280.isMeasuring()) { } //計測終了待ちloop // read out the data - must do this before calling the getxxxxx routines BME280.readMeasurements(); // 結果読み出し temp = BME280.getTemperature(); // 必ず温度を最初に読むこと humidity = BME280.getHumidity(); pressure = BME280.getPressure(); Serial.print("Temp: "); Serial.println(temp); Serial.print("Humi: "); Serial.println(humidity); Serial.print("Pres: "); Serial.println(pressure); // TFT書き出し tft.setCursor(0 * 5, 3 * 8); tft.setTextSize(2); tft.setTextColor(ST7735_RED, ST7735_BLACK); tft.print("Temp: "); tft.println(temp); tft.setTextSize(2); tft.setTextColor(ST7735_CYAN, ST7735_BLACK); tft.print("Humi: "); tft.println(humidity); tft.setTextSize(2); tft.setTextColor(ST7735_YELLOW, ST7735_BLACK); tft.print("Pres: "); tft.println(pressure); if(mode) { // SD書き出し File LogFile = SD.open("logTemp.txt", FILE_WRITE); if (LogFile) { Serial.println("Write out SD card..."); DateTime now = Rtc.now(); String value = String(now.year(), DEC) + "/" + (now.month() < 10 ? "0" : "") + String(now.month()) + "/" + (now.day() < 10 ? "0" : "") + String(now.day()) + " " + (now.hour() < 10 ? "0" : "") + String(now.hour()) + ":" + (now.minute() < 10 ? "0" : "") + String(now.minute()) + ":" + (now.second() < 10 ? "0" : "") + String(now.second()); value = value + "," + temp + "," + humidity + "," + pressure; LogFile.println(value); LogFile.close(); } else { tftdrawComment("Can't open LogTemp.txt", ST7735_RED); } } } /* ----- Set DateTime by NTP ------- */ void reSetTimeByNTP() { // NTPで時間再調整 DateTime now0 = Rtc.now(); if(now0.unixtime() < LastUpdate.unixtime() + ntpinterval * SECS_PER_MIN) return; tftdrawComment("Reset DateTime by NTP.", ST7735_YELLOW); SetTimeByNTP(); } void SetTimeByNTP() { // SampleのNTPClientより // NTPを使ってRTCを再設定 udp.begin(localPort); if(!timeServerIP) { WiFi.hostByName(ntpServerName, timeServerIP); DBG_PORT.print("NTP IP= "); DBG_PORT.println(timeServerIP); } else { DBG_PORT.print("already get IP= "); DBG_PORT.println(timeServerIP); } sendNTPpacket(timeServerIP); // send an NTP packet to a time server delay(1000); // wait to see if a reply is available int cb = udp.parsePacket(); if (!cb) { DBG_PORT.println("no packet yet"); tftdrawComment("no packet yet", ST7735_RED); flagntp = false; if (flagdbg) delay(2000); // 表示Delay(なくてもOK) } else { DBG_PORT.print("packet received, length="); tftdrawComment("NTP packet received !", ST7735_WHITE); DBG_PORT.println(cb); udp.read(packetBuffer, NTP_PACKET_SIZE); // バッファに受信データを読み込む unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); unsigned long secsSince1900 = highWord << 16 | lowWord; DBG_PORT.print("Seconds since Jan 1 1900 = " ); DBG_PORT.println(secsSince1900); DBG_PORT.print("Unix time = "); const unsigned long seventyYears = 2208988800UL; // 1900年から1970年の70年を秒で表すと2208988800秒になる unsigned long epoch = secsSince1900 - seventyYears; // NTPタイムスタンプから70年分の秒を引くとUNIXタイムが得られる DBG_PORT.println(epoch); // print Unix time: // print the hour, minute and second: DBG_PORT.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) DBG_PORT.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) DBG_PORT.print(':'); if ( ((epoch % 3600) / 60) < 10 ) { DBG_PORT.print('0'); // In the first 10 minutes of each hour, we'll want a leading '0' } DBG_PORT.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) DBG_PORT.print(':'); if ( (epoch % 60) < 10 ) { DBG_PORT.print('0'); // In the first 10 seconds of each minute, we'll want a leading '0' } DBG_PORT.println(epoch % 60); // print the second //setTime(epoch + LocalTimeOffset * SECS_PER_HOUR); // 内部時計に日時書き込み(Time.h) Rtc.adjust(DateTime(epoch + LocalTimeOffset * SECS_PER_HOUR)); // RTCに日時設定(RTCLib_2.h用) flagntp = true; } LastUpdate = Rtc.now(); } // send an NTP request to the time server at the given address unsigned long sendNTPpacket(IPAddress& address) { DBG_PORT.println("sending NTP packet..."); // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: udp.beginPacket(address, 123); //NTP requests are to port 123 udp.write(packetBuffer, NTP_PACKET_SIZE); udp.endPacket(); } /* ----- SD WebServer ------- */ void returnOK() { server.sendHeader("Connection", "close"); server.sendHeader("Access-Control-Allow-Origin", "*"); server.send(200, "text/plain", ""); } void returnFail(String msg) { server.sendHeader("Connection", "close"); server.sendHeader("Access-Control-Allow-Origin", "*"); 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()) { Serial.println("Sent less data than expected!"); } dataFile.close(); return true; } void handleFileUpload(){ if(server.uri() != "/edit") return; HTTPUpload& upload = server.upload(); if(upload.status == UPLOAD_FILE_START){ if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str()); uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE); Serial.print("Upload: START, filename: "); Serial.println(upload.filename); } else if(upload.status == UPLOAD_FILE_WRITE){ if(uploadFile) uploadFile.write(upload.buf, upload.currentSize); Serial.print("Upload: WRITE, Bytes: "); Serial.println(upload.currentSize); } else if(upload.status == UPLOAD_FILE_END){ if(uploadFile) uploadFile.close(); Serial.print("Upload: END, Size: "); Serial.println(upload.totalSize); } } void deleteRecursive(String path){ File file = SD.open((char *)path.c_str()); if(!file.isDirectory()){ file.close(); SD.remove((char *)path.c_str()); return; } file.rewindDirectory(); while(true) { File entry = file.openNextFile(); if (!entry) break; String entryPath = path + "/" +entry.name(); if(entry.isDirectory()){ entry.close(); deleteRecursive(entryPath); } else { entry.close(); SD.remove((char *)entryPath.c_str()); } yield(); } SD.rmdir((char *)path.c_str()); file.close(); } void handleDelete(){ if(server.args() == 0) return returnFail("BAD ARGS"); String path = server.arg(0); if(path == "/" || !SD.exists((char *)path.c_str())) { returnFail("BAD PATH"); return; } deleteRecursive(path); returnOK(); } void handleCreate(){ if(server.args() == 0) return returnFail("BAD ARGS"); String path = server.arg(0); if(path == "/" || SD.exists((char *)path.c_str())) { returnFail("BAD PATH"); return; } if(path.indexOf('.') > 0){ File file = SD.open((char *)path.c_str(), FILE_WRITE); if(file){ file.write((const char *)0); file.close(); } } else { SD.mkdir((char *)path.c_str()); } returnOK(); } void printDirectory() { if(!server.hasArg("dir")) return returnFail("BAD ARGS"); String path = server.arg("dir"); if(path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH"); File dir = SD.open((char *)path.c_str()); path = String(); if(!dir.isDirectory()){ dir.close(); return returnFail("NOT DIR"); } dir.rewindDirectory(); server.setContentLength(CONTENT_LENGTH_UNKNOWN); server.send(200, "text/json", ""); WiFiClient client = server.client(); server.sendContent("["); for (int cnt = 0; true; ++cnt) { File entry = dir.openNextFile(); if (!entry) break; String output; if (cnt > 0) output = ','; output += "{\"type\":\""; output += (entry.isDirectory()) ? "dir" : "file"; output += "\",\"name\":\""; output += entry.name(); output += "\""; output += "}"; server.sendContent(output); entry.close(); } server.sendContent("]"); dir.close(); } 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); Serial.print(message); }
な,感じ。
コメント 0