/* *************************************************************************** ** Program : restAPI ** Version : v0.4.2 ** ** Copyright (c) 2020 Robert van den Breemen ** based on Framework ESP8266 from Willem Aandewiel ** ** TERMS OF USE: MIT License. See bottom of file. *************************************************************************** */ //======================================================================= void processAPI() { char fName[40] = ""; char URI[50] = ""; String words[10]; strlcpy( URI, httpServer.uri().c_str(), sizeof(URI) ); if (httpServer.method() == HTTP_GET) DebugTf("from[%s] URI[%s] method[GET] \r\n" , httpServer.client().remoteIP().toString().c_str() , URI); else DebugTf("from[%s] URI[%s] method[PUT] \r\n" , httpServer.client().remoteIP().toString().c_str() , URI); if (ESP.getFreeHeap() < 8500) // to prevent firmware from crashing! { DebugTf("==> Bailout due to low heap (%d bytes))\r\n", ESP.getFreeHeap() ); httpServer.send(500, "text/plain", "500: internal server error (low heap)\r\n"); return; } int8_t wc = splitString(URI, '/', words, 10); if (Verbose) { DebugT(">>"); for (int w=0; w [%s], ", w, words[w].c_str()); } Debugln(" "); } if (words[1] != "api") { sendApiNotFound(URI); return; } if (words[2] != "v0") { sendApiNotFound(URI); return; } if (words[3] == "otgw") { //what the heck should I do? // /api/v0/otgw/{msgid} msgid = OpenTherm Message Id // Response: label, value, unit // { // "label": "Tr", // "value": "0.00", // "unit": "°C" // } sendOTGWvalue(words[4].toInt()); } else if (words[3] == "devinfo") { sendDeviceInfo(); } else if (words[3] == "devtime") { sendDeviceTime(); } else if (words[3] == "settings") { if (httpServer.method() == HTTP_PUT || httpServer.method() == HTTP_POST) { postSettings(); } else { sendDeviceSettings(); } } else sendApiNotFound(URI); } // processAPI() //====[ implementing REST API ]==== void sendOTGWvalue(int msgid){ StaticJsonDocument<256> doc; JsonObject root = doc.to(); if (OTmap[msgid].type==ot_undef) { //message is undefined, return error root["error"] = "message undefined: reserved for future use"; } else if (msgid>= 0 && msgid<=127) { //message id's need to be between 0 and 127 //Debug print the values first DebugTf("%s = %s %s\r\n", OTmap[msgid].label, getOTGWValue(msgid).c_str(), OTmap[msgid].unit); //build the json root["label"] = OTmap[msgid].label; if (OTmap[msgid].type == ot_f88) { root["value"] = getOTGWValue(msgid).toFloat(); } else {// all other message types convert to integer root["value"] = getOTGWValue(msgid).toInt(); } root["unit"] = OTmap[msgid].unit; } else { root["error"] = "message id > 127: reserved for future use"; } String sBuff; serializeJsonPretty(root, sBuff); //DebugTf("Json = %s\r\n", sBuff.c_str()); //reply with json httpServer.sendHeader("Access-Control-Allow-Origin", "*"); httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); httpServer.send(200, "application/json", sBuff); } //======================================================================= void sendDeviceInfo() { sendStartJsonObj("devinfo"); sendNestedJsonObj("author", "Robert van den Breemen"); sendNestedJsonObj("fwversion", _FW_VERSION); snprintf(cMsg, sizeof(cMsg), "%s %s", __DATE__, __TIME__); sendNestedJsonObj("compiled", cMsg); sendNestedJsonObj("hostname", settingHostname); sendNestedJsonObj("ipaddress", WiFi.localIP().toString().c_str()); sendNestedJsonObj("macaddress", WiFi.macAddress().c_str()); sendNestedJsonObj("freeheap", ESP.getFreeHeap()); sendNestedJsonObj("maxfreeblock", ESP.getMaxFreeBlockSize()); sendNestedJsonObj("chipid", String( ESP.getChipId(), HEX ).c_str()); sendNestedJsonObj("coreversion", String( ESP.getCoreVersion() ).c_str() ); sendNestedJsonObj("sdkversion", String( ESP.getSdkVersion() ).c_str()); sendNestedJsonObj("cpufreq", ESP.getCpuFreqMHz()); sendNestedJsonObj("sketchsize", formatFloat( (ESP.getSketchSize() / 1024.0), 3)); sendNestedJsonObj("freesketchspace", formatFloat( (ESP.getFreeSketchSpace() / 1024.0), 3)); snprintf(cMsg, sizeof(cMsg), "%08X", ESP.getFlashChipId()); sendNestedJsonObj("flashchipid", cMsg); // flashChipId sendNestedJsonObj("flashchipsize", formatFloat((ESP.getFlashChipSize() / 1024.0 / 1024.0), 3)); sendNestedJsonObj("flashchiprealsize", formatFloat((ESP.getFlashChipRealSize() / 1024.0 / 1024.0), 3)); SPIFFS.info(SPIFFSinfo); sendNestedJsonObj("spiffssize", formatFloat( (SPIFFSinfo.totalBytes / (1024.0 * 1024.0)), 0)); sendNestedJsonObj("flashchipspeed", formatFloat((ESP.getFlashChipSpeed() / 1000.0 / 1000.0), 0)); FlashMode_t ideMode = ESP.getFlashChipMode(); sendNestedJsonObj("flashchipmode", flashMode[ideMode]); sendNestedJsonObj("boardtype", #ifdef ARDUINO_ESP8266_NODEMCU "ESP8266_NODEMCU" #endif #ifdef ARDUINO_ESP8266_GENERIC "ESP8266_GENERIC" #endif #ifdef ESP8266_ESP01 "ESP8266_ESP01" #endif #ifdef ESP8266_ESP12 "ESP8266_ESP12" #endif ); sendNestedJsonObj("ssid", WiFi.SSID().c_str()); sendNestedJsonObj("wifirssi", WiFi.RSSI()); //sendNestedJsonObj("uptime", upTime()); sendNestedJsonObj("lastreset", lastReset); httpServer.sendContent("\r\n]}\r\n"); } // sendDeviceInfo() //======================================================================= void sendDeviceTime() { char actTime[50]; sendStartJsonObj("devtime"); snprintf(actTime, 49, "%04d-%02d-%02d %02d:%02d:%02d", year(), month(), day() , hour(), minute(), second()); sendNestedJsonObj("dateTime", actTime); sendNestedJsonObj("epoch", (int)now()); sendEndJsonObj(); } // sendDeviceTime() //======================================================================= void sendDeviceSettings() { DebugTln("sending device settings ...\r"); sendStartJsonObj("settings"); sendJsonSettingObj("hostname", settingHostname, "s", sizeof(settingHostname) -1); //sendJsonSettingObj("float", settingFloat, "f", 0, 10, 5); //sendJsonSettingObj("intager", settingInteger , "i", 2, 60); sendEndJsonObj(); } // sendDeviceSettings() //======================================================================= void postSettings() { //------------------------------------------------------------ // json string: {"name":"settingInterval","value":9} // json string: {"name":"settingHostname","value":"abc"} //------------------------------------------------------------ // so, why not use ArduinoJSON library? // I say: try it yourself ;-) It won't be easy String wOut[5]; String wPair[5]; String jsonIn = httpServer.arg(0).c_str(); char field[25] = ""; char newValue[101]=""; jsonIn.replace("{", ""); jsonIn.replace("}", ""); jsonIn.replace("\"", ""); int8_t wp = splitString(jsonIn.c_str(), ',', wPair, 5) ; for (int i=0; i pair[%s]\r\n", i, wPair[i].c_str()); int8_t wc = splitString(wPair[i].c_str(), ':', wOut, 5) ; //DebugTf("==> [%s] -> field[%s]->val[%s]\r\n", wPair[i].c_str(), wOut[0].c_str(), wOut[1].c_str()); if (wOut[0].equalsIgnoreCase("name")) strCopy(field, sizeof(field), wOut[1].c_str()); if (wOut[0].equalsIgnoreCase("value")) strCopy(newValue, sizeof(newValue), wOut[1].c_str()); } DebugTf("--> field[%s] => newValue[%s]\r\n", field, newValue); updateSetting(field, newValue); httpServer.send(200, "application/json", httpServer.arg(0)); } // postSettings() //==================================================== void sendApiNotFound(const char *URI) { httpServer.sendHeader("Access-Control-Allow-Origin", "*"); httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); httpServer.send ( 404, "text/html", ""); strlcpy(cMsg, "", sizeof(cMsg)); httpServer.sendContent(cMsg); strlcpy(cMsg, "

OTGW firmware

", sizeof(cMsg)); httpServer.sendContent(cMsg); strlcpy(cMsg, "
[", sizeof(cMsg)); strlcat(cMsg, URI, sizeof(cMsg)); strlcat(cMsg, "] is not a valid ", sizeof(cMsg)); httpServer.sendContent(cMsg); strlcpy(cMsg, "\r\n", sizeof(cMsg)); httpServer.sendContent(cMsg); } // sendApiNotFound() /*************************************************************************** * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **************************************************************************** */