mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-01 09:19:38 +00:00
Use JSON library for Web UI REST Endpoints (#1340)
* Updated rest endpoint json handling. * Fixes, typos corrected. Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: Sacha Weatherstone <sachaw100@hotmail.com>
This commit is contained in:
parent
0c600363c8
commit
998c90d326
@ -8,10 +8,11 @@
|
|||||||
#include "mesh/http/WiFiAPClient.h"
|
#include "mesh/http/WiFiAPClient.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
#include <FSCommon.h>
|
||||||
#include <HTTPBodyParser.hpp>
|
#include <HTTPBodyParser.hpp>
|
||||||
#include <HTTPMultipartBodyParser.hpp>
|
#include <HTTPMultipartBodyParser.hpp>
|
||||||
#include <HTTPURLEncodedBodyParser.hpp>
|
#include <HTTPURLEncodedBodyParser.hpp>
|
||||||
#include <FSCommon.h>
|
#include <json11.hpp>
|
||||||
|
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
#include "esp_task_wdt.h"
|
#include "esp_task_wdt.h"
|
||||||
@ -272,8 +273,6 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
|
|||||||
DEBUG_MSG("webAPI handleAPIv1ToRadio\n");
|
DEBUG_MSG("webAPI handleAPIv1ToRadio\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool firstFile = 1;
|
|
||||||
|
|
||||||
void htmlDeleteDir(const char * dirname)
|
void htmlDeleteDir(const char * dirname)
|
||||||
{
|
{
|
||||||
File root = FSCom.open(dirname);
|
File root = FSCom.open(dirname);
|
||||||
@ -301,70 +300,72 @@ void htmlDeleteDir(const char * dirname)
|
|||||||
root.close();
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void htmlListDir(HTTPResponse *res, const char * dirname, uint8_t levels)
|
std::vector<std::map<char *, char *>>* htmlListDir(std::vector<std::map<char *, char *>> *fileList, const char *dirname, uint8_t levels)
|
||||||
{
|
{
|
||||||
File root = FSCom.open(dirname);
|
File root = FSCom.open(dirname);
|
||||||
if(!root){
|
if(!root){
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(!root.isDirectory()){
|
if(!root.isDirectory()){
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// iterate over the file list
|
||||||
File file = root.openNextFile();
|
File file = root.openNextFile();
|
||||||
while(file){
|
while(file){
|
||||||
if(file.isDirectory() && !String(file.name()).endsWith(".")) {
|
if(file.isDirectory() && !String(file.name()).endsWith(".")) {
|
||||||
if(levels){
|
if(levels){
|
||||||
htmlListDir(res, file.name(), levels -1);
|
htmlListDir(fileList, file.name(), levels -1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (firstFile) {
|
std::map<char*, char*> thisFileMap;
|
||||||
firstFile = 0;
|
thisFileMap[strdup("size")] = strdup(String(file.size()).c_str());
|
||||||
} else {
|
thisFileMap[strdup("name")] = strdup(String(file.name()).substring(1).c_str());
|
||||||
res->println(",");
|
|
||||||
}
|
|
||||||
res->println("{");
|
|
||||||
if (String(file.name()).substring(1).endsWith(".gz")) {
|
if (String(file.name()).substring(1).endsWith(".gz")) {
|
||||||
String modifiedFile = String(file.name()).substring(1);
|
String modifiedFile = String(file.name()).substring(1);
|
||||||
modifiedFile.remove((modifiedFile.length() - 3), 3);
|
modifiedFile.remove((modifiedFile.length() - 3), 3);
|
||||||
res->print("\"nameModified\": \"" + modifiedFile + "\",");
|
thisFileMap[strdup("nameModified")] = strdup(modifiedFile.c_str());
|
||||||
res->print("\"name\": \"" + String(file.name()).substring(1) + "\",");
|
|
||||||
} else {
|
|
||||||
res->print("\"name\": \"" + String(file.name()).substring(1) + "\",");
|
|
||||||
}
|
}
|
||||||
res->print("\"size\": " + String(file.size()));
|
fileList->push_back(thisFileMap);
|
||||||
res->print("}");
|
|
||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
file = root.openNextFile();
|
file = root.openNextFile();
|
||||||
}
|
}
|
||||||
root.close();
|
root.close();
|
||||||
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
|
||||||
{
|
{
|
||||||
|
|
||||||
res->setHeader("Content-Type", "application/json");
|
res->setHeader("Content-Type", "application/json");
|
||||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||||
res->println("{");
|
|
||||||
res->println("\"data\": {");
|
|
||||||
res->print("\"files\": [");
|
|
||||||
htmlListDir(res, "/", 10);
|
|
||||||
res->print("],");
|
|
||||||
res->print("\"filesystem\" : {");
|
|
||||||
res->print("\"total\" : " + String(FSCom.totalBytes()) + ",");
|
|
||||||
res->print("\"used\" : " + String(FSCom.usedBytes()) + ",");
|
|
||||||
res->print("\"free\" : " + String(FSCom.totalBytes() - FSCom.usedBytes()));
|
|
||||||
res->println("}");
|
|
||||||
res->println("},");
|
|
||||||
res->println("\"status\": \"ok\"");
|
|
||||||
res->println("}");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
using namespace json11;
|
||||||
|
auto fileList = htmlListDir(new std::vector<std::map<char *, char *>>(), "/", 10);
|
||||||
|
|
||||||
|
// create json output structure
|
||||||
|
Json filesystemObj = Json::object{
|
||||||
|
{"total", String(FSCom.totalBytes()).c_str()},
|
||||||
|
{"used", String(FSCom.usedBytes()).c_str()},
|
||||||
|
{"free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()},
|
||||||
|
};
|
||||||
|
|
||||||
|
Json jsonObjInner = Json::object{{"files", Json(*fileList)},
|
||||||
|
{"filesystem", filesystemObj}
|
||||||
|
};
|
||||||
|
|
||||||
|
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
|
||||||
|
|
||||||
|
// serialize and write it to the stream
|
||||||
|
std::string jsonStr = jsonObjOuter.dump();
|
||||||
|
res->print(jsonStr.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
||||||
{
|
{
|
||||||
|
using namespace json11;
|
||||||
|
|
||||||
ResourceParameters *params = req->getParams();
|
ResourceParameters *params = req->getParams();
|
||||||
std::string paramValDelete;
|
std::string paramValDelete;
|
||||||
|
|
||||||
@ -375,15 +376,15 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
|
|||||||
std::string pathDelete = "/" + paramValDelete;
|
std::string pathDelete = "/" + paramValDelete;
|
||||||
if (FSCom.remove(pathDelete.c_str())) {
|
if (FSCom.remove(pathDelete.c_str())) {
|
||||||
Serial.println(pathDelete.c_str());
|
Serial.println(pathDelete.c_str());
|
||||||
res->println("{");
|
Json jsonObjOuter = Json::object{{"status", "ok"}};
|
||||||
res->println("\"status\": \"ok\"");
|
std::string jsonStr = jsonObjOuter.dump();
|
||||||
res->println("}");
|
res->print(jsonStr.c_str());
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Serial.println(pathDelete.c_str());
|
Serial.println(pathDelete.c_str());
|
||||||
res->println("{");
|
Json jsonObjOuter = Json::object{{"status", "Error"}};
|
||||||
res->println("\"status\": \"Error\"");
|
std::string jsonStr = jsonObjOuter.dump();
|
||||||
res->println("}");
|
res->print(jsonStr.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -600,6 +601,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
void handleReport(HTTPRequest *req, HTTPResponse *res)
|
void handleReport(HTTPRequest *req, HTTPResponse *res)
|
||||||
{
|
{
|
||||||
|
using namespace json11;
|
||||||
|
|
||||||
ResourceParameters *params = req->getParams();
|
ResourceParameters *params = req->getParams();
|
||||||
std::string content;
|
std::string content;
|
||||||
@ -618,104 +620,89 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
|
|||||||
res->println("<pre>");
|
res->println("<pre>");
|
||||||
}
|
}
|
||||||
|
|
||||||
res->println("{");
|
// data->airtime->tx_log
|
||||||
|
std::vector<String> txLogValues;
|
||||||
res->println("\"data\": {");
|
|
||||||
|
|
||||||
res->println("\"airtime\": {");
|
|
||||||
|
|
||||||
uint32_t *logArray;
|
uint32_t *logArray;
|
||||||
|
|
||||||
res->print("\"tx_log\": [");
|
|
||||||
|
|
||||||
logArray = airTime->airtimeReport(TX_LOG);
|
logArray = airTime->airtimeReport(TX_LOG);
|
||||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
tmp = *(logArray + i);
|
tmp = *(logArray + i);
|
||||||
res->printf("%d", tmp);
|
txLogValues.push_back(String(tmp));
|
||||||
if (i != airTime->getPeriodsToLog() - 1) {
|
|
||||||
res->print(", ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res->println("],");
|
// data->airtime->rx_log
|
||||||
res->print("\"rx_log\": [");
|
std::vector<String> rxLogValues;
|
||||||
|
|
||||||
logArray = airTime->airtimeReport(RX_LOG);
|
logArray = airTime->airtimeReport(RX_LOG);
|
||||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
tmp = *(logArray + i);
|
tmp = *(logArray + i);
|
||||||
res->printf("%d", tmp);
|
rxLogValues.push_back(String(tmp));
|
||||||
if (i != airTime->getPeriodsToLog() - 1) {
|
|
||||||
res->print(", ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res->println("],");
|
// data->airtime->rx_all_log
|
||||||
res->print("\"rx_all_log\": [");
|
std::vector<String> rxAllLogValues;
|
||||||
|
|
||||||
logArray = airTime->airtimeReport(RX_ALL_LOG);
|
logArray = airTime->airtimeReport(RX_ALL_LOG);
|
||||||
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
for (int i = 0; i < airTime->getPeriodsToLog(); i++) {
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
tmp = *(logArray + i);
|
tmp = *(logArray + i);
|
||||||
res->printf("%d", tmp);
|
rxAllLogValues.push_back(String(tmp));
|
||||||
if (i != airTime->getPeriodsToLog() - 1) {
|
|
||||||
res->print(", ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res->println("],");
|
Json jsonObjAirtime = Json::object{
|
||||||
res->printf("\"channel_utilization\": %3.2f%,\n", airTime->channelUtilizationPercent());
|
{"tx_log", Json(txLogValues)},
|
||||||
res->printf("\"utilization_tx\": %3.2f%,\n", airTime->utilizationTXPercent());
|
{"rx_log", Json(rxLogValues)},
|
||||||
res->printf("\"seconds_since_boot\": %u,\n", airTime->getSecondsSinceBoot());
|
{"rx_all_log", Json(rxAllLogValues)},
|
||||||
res->printf("\"seconds_per_period\": %u,\n", airTime->getSecondsPerPeriod());
|
{"channel_utilization", Json(airTime->channelUtilizationPercent())},
|
||||||
res->printf("\"periods_to_log\": %u\n", airTime->getPeriodsToLog());
|
{"utilization_tx", Json(airTime->utilizationTXPercent())},
|
||||||
|
{"seconds_since_boot", Json(int(airTime->getSecondsSinceBoot()))},
|
||||||
res->println("},");
|
{"seconds_per_period", Json(int(airTime->getSecondsPerPeriod()))},
|
||||||
|
{"periods_to_log", Json(airTime->getPeriodsToLog())},
|
||||||
res->println("\"wifi\": {");
|
};
|
||||||
|
|
||||||
res->println("\"rssi\": " + String(WiFi.RSSI()) + ",");
|
|
||||||
|
|
||||||
|
// data->wifi
|
||||||
|
String ipStr;
|
||||||
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
|
if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
|
||||||
res->println("\"ip\": \"" + String(WiFi.softAPIP().toString().c_str()) + "\"");
|
ipStr = String(WiFi.softAPIP().toString());
|
||||||
} else {
|
} else {
|
||||||
res->println("\"ip\": \"" + String(WiFi.localIP().toString().c_str()) + "\"");
|
ipStr = String(WiFi.localIP().toString());
|
||||||
}
|
}
|
||||||
|
Json jsonObjWifi = Json::object{
|
||||||
|
{"rssi", String(WiFi.RSSI())},
|
||||||
|
{"ip", ipStr.c_str()}
|
||||||
|
};
|
||||||
|
|
||||||
res->println("},");
|
// data->memory
|
||||||
|
Json jsonObjMemory = Json::object{{"heap_total", Json(int(ESP.getHeapSize()))},
|
||||||
|
{"heap_free", Json(int(ESP.getFreeHeap()))},
|
||||||
|
{"psram_total", Json(int(ESP.getPsramSize()))},
|
||||||
|
{"psram_free", Json(int(ESP.getFreePsram()))},
|
||||||
|
{"fs_total", String(FSCom.totalBytes()).c_str()},
|
||||||
|
{"fs_used", String(FSCom.usedBytes()).c_str()},
|
||||||
|
{"fs_free", String(FSCom.totalBytes() - FSCom.usedBytes()).c_str()}};
|
||||||
|
|
||||||
res->println("\"memory\": {");
|
// data->power
|
||||||
res->printf("\"heap_total\": %d,\n", ESP.getHeapSize());
|
Json jsonObjPower = Json::object{{"battery_percent", Json(powerStatus->getBatteryChargePercent())},
|
||||||
res->printf("\"heap_free\": %d,\n", ESP.getFreeHeap());
|
{"battery_voltage_mv", Json(powerStatus->getBatteryVoltageMv())},
|
||||||
res->printf("\"psram_total\": %d,\n", ESP.getPsramSize());
|
{"has_battery", BoolToString(powerStatus->getHasBattery())},
|
||||||
res->printf("\"psram_free\": %d,\n", ESP.getFreePsram());
|
{"has_usb", BoolToString(powerStatus->getHasUSB())},
|
||||||
res->println("\"fs_total\" : " + String(FSCom.totalBytes()) + ",");
|
{"is_charging", BoolToString(powerStatus->getIsCharging())}};
|
||||||
res->println("\"fs_used\" : " + String(FSCom.usedBytes()) + ",");
|
|
||||||
res->println("\"fs_free\" : " + String(FSCom.totalBytes() - FSCom.usedBytes()));
|
|
||||||
res->println("},");
|
|
||||||
|
|
||||||
res->println("\"power\": {");
|
// data->device
|
||||||
res->printf("\"battery_percent\": %u,\n", powerStatus->getBatteryChargePercent());
|
Json jsonObjDevice = Json::object{{"reboot_counter", Json(int(myNodeInfo.reboot_count))}};
|
||||||
res->printf("\"battery_voltage_mv\": %u,\n", powerStatus->getBatteryVoltageMv());
|
|
||||||
res->printf("\"has_battery\": %s,\n", BoolToString(powerStatus->getHasBattery()));
|
|
||||||
res->printf("\"has_usb\": %s,\n", BoolToString(powerStatus->getHasUSB()));
|
|
||||||
res->printf("\"is_charging\": %s\n", BoolToString(powerStatus->getIsCharging()));
|
|
||||||
res->println("},");
|
|
||||||
|
|
||||||
res->println("\"device\": {");
|
// data->radio
|
||||||
res->printf("\"reboot_counter\": %d\n", myNodeInfo.reboot_count);
|
Json jsonObjRadio = Json::object{{"frequency", Json(RadioLibInterface::instance->getFreq())},
|
||||||
res->println("},");
|
{"lora_channel", Json(int(RadioLibInterface::instance->getChannelNum()))}};
|
||||||
|
|
||||||
res->println("\"radio\": {");
|
// collect data to inner data object
|
||||||
res->printf("\"frequecy\": %f,\n", RadioLibInterface::instance->getFreq());
|
Json jsonObjInner = Json::object{{"airtime", jsonObjAirtime}, {"wifi", jsonObjWifi}, {"memory", jsonObjMemory},
|
||||||
res->printf("\"lora_channel\": %d\n", RadioLibInterface::instance->getChannelNum());
|
{"power", jsonObjPower}, {"device", jsonObjDevice}, {"radio", jsonObjRadio}};
|
||||||
res->println("}");
|
|
||||||
|
|
||||||
res->println("},");
|
// create json output structure
|
||||||
|
Json jsonObjOuter = Json::object{{"data", jsonObjInner}, {"status", "ok"}};
|
||||||
res->println("\"status\": \"ok\"");
|
// serialize and write it to the stream
|
||||||
res->println("}");
|
std::string jsonStr = jsonObjOuter.dump();
|
||||||
|
res->print(jsonStr.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -912,6 +899,8 @@ void handleRestart(HTTPRequest *req, HTTPResponse *res)
|
|||||||
|
|
||||||
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
||||||
{
|
{
|
||||||
|
using namespace json11;
|
||||||
|
|
||||||
res->setHeader("Content-Type", "application/json");
|
res->setHeader("Content-Type", "application/json");
|
||||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res->setHeader("Access-Control-Allow-Methods", "POST");
|
res->setHeader("Access-Control-Allow-Methods", "POST");
|
||||||
@ -938,28 +927,25 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
|
|||||||
screen->blink();
|
screen->blink();
|
||||||
}
|
}
|
||||||
|
|
||||||
res->println("{");
|
Json jsonObjOuter = Json::object{{"status", "ok"}};
|
||||||
res->println("\"status\": \"ok\"");
|
std::string jsonStr = jsonObjOuter.dump();
|
||||||
res->println("}");
|
res->print(jsonStr.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
||||||
{
|
{
|
||||||
|
using namespace json11;
|
||||||
|
|
||||||
res->setHeader("Content-Type", "application/json");
|
res->setHeader("Content-Type", "application/json");
|
||||||
res->setHeader("Access-Control-Allow-Origin", "*");
|
res->setHeader("Access-Control-Allow-Origin", "*");
|
||||||
res->setHeader("Access-Control-Allow-Methods", "GET");
|
res->setHeader("Access-Control-Allow-Methods", "GET");
|
||||||
// res->setHeader("Content-Type", "text/html");
|
// res->setHeader("Content-Type", "text/html");
|
||||||
|
|
||||||
int n = WiFi.scanNetworks();
|
int n = WiFi.scanNetworks();
|
||||||
res->println("{");
|
|
||||||
res->println("\"data\": {");
|
|
||||||
if (n == 0) {
|
|
||||||
// No networks found.
|
|
||||||
res->println("\"networks\": []");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
res->println("\"networks\": [");
|
|
||||||
|
|
||||||
|
// build list of network objects
|
||||||
|
std::vector<Json> networkObjs;
|
||||||
|
if (n > 0) {
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
char ssidArray[50];
|
char ssidArray[50];
|
||||||
String ssidString = String(WiFi.SSID(i));
|
String ssidString = String(WiFi.SSID(i));
|
||||||
@ -967,19 +953,20 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
|
|||||||
ssidString.toCharArray(ssidArray, 50);
|
ssidString.toCharArray(ssidArray, 50);
|
||||||
|
|
||||||
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
|
if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) {
|
||||||
res->printf("{\"ssid\": \"%s\",\"rssi\": %d}", ssidArray, WiFi.RSSI(i));
|
Json thisNetwork = Json::object{{"ssid", ssidArray}, {"rssi", WiFi.RSSI(i)}};
|
||||||
if (i != n - 1) {
|
networkObjs.push_back(thisNetwork);
|
||||||
res->printf(",");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Yield some cpu cycles to IP stack.
|
// Yield some cpu cycles to IP stack.
|
||||||
// This is important in case the list is large and it takes us time to return
|
// This is important in case the list is large and it takes us time to return
|
||||||
// to the main loop.
|
// to the main loop.
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
res->println("]");
|
|
||||||
}
|
}
|
||||||
res->println("},");
|
|
||||||
res->println("\"status\": \"ok\"");
|
// build output structure
|
||||||
res->println("}");
|
Json jsonObjOuter = Json::object{{"data", networkObjs}, {"status", "ok"}};
|
||||||
|
|
||||||
|
// serialize and write it to the stream
|
||||||
|
std::string jsonStr = jsonObjOuter.dump();
|
||||||
|
res->print(jsonStr.c_str());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user