mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-09-13 01:56:19 +00:00
484 lines
15 KiB
Arduino
484 lines
15 KiB
Arduino
#include "src/Globals/Nodes.h"
|
|
#include "src/Globals/Device.h"
|
|
#include "src/Globals/Plugins.h"
|
|
#include "StringProviderTypes.h"
|
|
|
|
// ********************************************************************************
|
|
// Web Interface get CSV value from task
|
|
// ********************************************************************************
|
|
void handle_csvval()
|
|
{
|
|
String htmlData;
|
|
htmlData.reserve(25); // Reserve for error message
|
|
const int printHeader = getFormItemInt(F("header"), 1);
|
|
bool printHeaderValid = true;
|
|
if (printHeader != 1 && printHeader != 0)
|
|
{
|
|
htmlData = F("ERROR: Header not valid!\n");
|
|
printHeaderValid = false;
|
|
}
|
|
|
|
const taskIndex_t taskNr = getFormItemInt(F("tasknr"), INVALID_TASK_INDEX);
|
|
const bool taskValid = validTaskIndex(taskNr);
|
|
if (!taskValid)
|
|
{
|
|
htmlData = F("ERROR: TaskNr not valid!\n");
|
|
}
|
|
|
|
const int INVALID_VALUE_NUM = INVALID_TASKVAR_INDEX + 1;
|
|
const taskVarIndex_t valNr = getFormItemInt(F("valnr"), INVALID_VALUE_NUM);
|
|
bool valueNumberValid = true;
|
|
if (valNr != INVALID_VALUE_NUM && !validTaskVarIndex(valNr))
|
|
{
|
|
htmlData = F("ERROR: ValueId not valid!\n");
|
|
valueNumberValid = false;
|
|
}
|
|
|
|
TXBuffer.startJsonStream();
|
|
if (taskValid && valueNumberValid && printHeaderValid)
|
|
{
|
|
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(taskNr);
|
|
|
|
if (validDeviceIndex(DeviceIndex))
|
|
{
|
|
LoadTaskSettings(taskNr);
|
|
byte taskValCount = Device[DeviceIndex].ValueCount;
|
|
uint16_t stringReserveSize = (valNr == INVALID_VALUE_NUM ? 1 : taskValCount) * 24;
|
|
htmlData.reserve(stringReserveSize);
|
|
|
|
if (printHeader)
|
|
{
|
|
for (byte x = 0; x < taskValCount; x++)
|
|
{
|
|
if (valNr == INVALID_VALUE_NUM || valNr == x)
|
|
{
|
|
htmlData += String(ExtraTaskSettings.TaskDeviceValueNames[x]);
|
|
if (x != taskValCount - 1)
|
|
{
|
|
htmlData += ';';
|
|
}
|
|
}
|
|
}
|
|
htmlData += '\n';
|
|
addHtml(htmlData);
|
|
htmlData = "";
|
|
}
|
|
|
|
for (byte x = 0; x < taskValCount; x++)
|
|
{
|
|
if (valNr == INVALID_VALUE_NUM || valNr == x)
|
|
{
|
|
htmlData += formatUserVarNoCheck(taskNr, x);
|
|
if (x != taskValCount - 1)
|
|
{
|
|
htmlData += ';';
|
|
}
|
|
}
|
|
}
|
|
htmlData += '\n';
|
|
}
|
|
}
|
|
addHtml(htmlData);
|
|
TXBuffer.endStream();
|
|
}
|
|
// ********************************************************************************
|
|
// Web Interface JSON page (no password!)
|
|
// ********************************************************************************
|
|
void handle_json()
|
|
{
|
|
const taskIndex_t taskNr = getFormItemInt(F("tasknr"), INVALID_TASK_INDEX);
|
|
const bool showSpecificTask = validTaskIndex(taskNr);
|
|
bool showSystem = true;
|
|
bool showWifi = true;
|
|
bool showDataAcquisition = true;
|
|
bool showTaskDetails = true;
|
|
bool showNodes = true;
|
|
{
|
|
String view = web_server.arg("view");
|
|
|
|
if (view.length() != 0) {
|
|
if (view == F("sensorupdate")) {
|
|
showSystem = false;
|
|
showWifi = false;
|
|
showDataAcquisition = false;
|
|
showTaskDetails = false;
|
|
showNodes = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
TXBuffer.startJsonStream();
|
|
|
|
if (!showSpecificTask)
|
|
{
|
|
addHtml("{");
|
|
|
|
if (showSystem) {
|
|
addHtml(F("\"System\":{\n"));
|
|
stream_next_json_object_value(LabelType::BUILD_DESC);
|
|
stream_next_json_object_value(LabelType::GIT_BUILD);
|
|
stream_next_json_object_value(LabelType::SYSTEM_LIBRARIES);
|
|
stream_next_json_object_value(LabelType::PLUGIN_COUNT);
|
|
stream_next_json_object_value(LabelType::PLUGIN_DESCRIPTION);
|
|
stream_next_json_object_value(LabelType::LOCAL_TIME);
|
|
stream_next_json_object_value(LabelType::UNIT_NR);
|
|
stream_next_json_object_value(LabelType::UNIT_NAME);
|
|
stream_next_json_object_value(LabelType::UPTIME);
|
|
stream_next_json_object_value(LabelType::BOOT_TYPE);
|
|
stream_next_json_object_value(LabelType::RESET_REASON);
|
|
|
|
if (wdcounter > 0)
|
|
{
|
|
stream_next_json_object_value(LabelType::LOAD_PCT);
|
|
stream_next_json_object_value(LabelType::LOOP_COUNT);
|
|
}
|
|
stream_next_json_object_value(LabelType::CPU_ECO_MODE);
|
|
|
|
#ifdef CORE_POST_2_5_0
|
|
stream_next_json_object_value(LabelType::HEAP_MAX_FREE_BLOCK);
|
|
stream_next_json_object_value(LabelType::HEAP_FRAGMENTATION);
|
|
#endif // ifdef CORE_POST_2_5_0
|
|
stream_last_json_object_value(LabelType::FREE_MEM);
|
|
addHtml(F(",\n"));
|
|
}
|
|
|
|
if (showWifi) {
|
|
addHtml(F("\"WiFi\":{\n"));
|
|
#if defined(ESP8266)
|
|
stream_next_json_object_value(LabelType::HOST_NAME);
|
|
#endif // if defined(ESP8266)
|
|
#ifdef FEATURE_MDNS
|
|
stream_next_json_object_value(LabelType::M_DNS);
|
|
#endif // ifdef FEATURE_MDNS
|
|
stream_next_json_object_value(LabelType::IP_CONFIG);
|
|
stream_next_json_object_value(LabelType::IP_ADDRESS);
|
|
stream_next_json_object_value(LabelType::IP_SUBNET);
|
|
stream_next_json_object_value(LabelType::GATEWAY);
|
|
stream_next_json_object_value(LabelType::STA_MAC);
|
|
stream_next_json_object_value(LabelType::DNS_1);
|
|
stream_next_json_object_value(LabelType::DNS_2);
|
|
stream_next_json_object_value(LabelType::SSID);
|
|
stream_next_json_object_value(LabelType::BSSID);
|
|
stream_next_json_object_value(LabelType::CHANNEL);
|
|
stream_next_json_object_value(LabelType::CONNECTED_MSEC);
|
|
stream_next_json_object_value(LabelType::LAST_DISCONNECT_REASON);
|
|
stream_next_json_object_value(LabelType::LAST_DISC_REASON_STR);
|
|
stream_next_json_object_value(LabelType::NUMBER_RECONNECTS);
|
|
stream_next_json_object_value(LabelType::FORCE_WIFI_BG);
|
|
stream_next_json_object_value(LabelType::RESTART_WIFI_LOST_CONN);
|
|
#ifdef ESP8266
|
|
stream_next_json_object_value(LabelType::FORCE_WIFI_NOSLEEP);
|
|
#endif // ifdef ESP8266
|
|
#ifdef SUPPORT_ARP
|
|
stream_next_json_object_value(LabelType::PERIODICAL_GRAT_ARP);
|
|
#endif // ifdef SUPPORT_ARP
|
|
stream_next_json_object_value(LabelType::CONNECTION_FAIL_THRESH);
|
|
stream_last_json_object_value(LabelType::WIFI_RSSI);
|
|
addHtml(F(",\n"));
|
|
}
|
|
|
|
if (showNodes) {
|
|
bool comma_between = false;
|
|
|
|
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it)
|
|
{
|
|
if (it->second.ip[0] != 0)
|
|
{
|
|
if (comma_between) {
|
|
addHtml(",");
|
|
} else {
|
|
comma_between = true;
|
|
addHtml(F("\"nodes\":[\n")); // open json array if >0 nodes
|
|
}
|
|
|
|
addHtml("{");
|
|
stream_next_json_object_value(F("nr"), String(it->first));
|
|
stream_next_json_object_value(F("name"),
|
|
(it->first != Settings.Unit) ? it->second.nodeName : Settings.Name);
|
|
|
|
if (it->second.build) {
|
|
stream_next_json_object_value(F("build"), String(it->second.build));
|
|
}
|
|
|
|
if (it->second.nodeType) {
|
|
String platform = getNodeTypeDisplayString(it->second.nodeType);
|
|
|
|
if (platform.length() > 0) {
|
|
stream_next_json_object_value(F("platform"), platform);
|
|
}
|
|
}
|
|
stream_next_json_object_value(F("ip"), it->second.ip.toString());
|
|
stream_last_json_object_value(F("age"), String(it->second.age));
|
|
} // if node info exists
|
|
} // for loop
|
|
|
|
if (comma_between) {
|
|
addHtml(F("],\n")); // close array if >0 nodes
|
|
}
|
|
}
|
|
}
|
|
|
|
taskIndex_t firstTaskIndex = 0;
|
|
taskIndex_t lastTaskIndex = TASKS_MAX - 1;
|
|
|
|
if (showSpecificTask)
|
|
{
|
|
firstTaskIndex = taskNr - 1;
|
|
lastTaskIndex = taskNr - 1;
|
|
}
|
|
taskIndex_t lastActiveTaskIndex = 0;
|
|
|
|
for (taskIndex_t TaskIndex = firstTaskIndex; TaskIndex <= lastTaskIndex; TaskIndex++) {
|
|
if (validPluginID_fullcheck(Settings.TaskDeviceNumber[TaskIndex])) {
|
|
lastActiveTaskIndex = TaskIndex;
|
|
}
|
|
}
|
|
|
|
if (!showSpecificTask) {
|
|
addHtml(F("\"Sensors\":[\n"));
|
|
}
|
|
|
|
// Keep track of the lowest reported TTL and use that as refresh interval.
|
|
unsigned long lowest_ttl_json = 60;
|
|
|
|
for (taskIndex_t TaskIndex = firstTaskIndex; TaskIndex <= lastActiveTaskIndex && validTaskIndex(TaskIndex); TaskIndex++)
|
|
{
|
|
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(TaskIndex);
|
|
|
|
if (validDeviceIndex(DeviceIndex))
|
|
{
|
|
const unsigned long taskInterval = Settings.TaskDeviceTimer[TaskIndex];
|
|
LoadTaskSettings(TaskIndex);
|
|
addHtml(F("{\n"));
|
|
|
|
unsigned long ttl_json = 60; // Default value
|
|
|
|
// For simplicity, do the optional values first.
|
|
if (Device[DeviceIndex].ValueCount != 0) {
|
|
if ((taskInterval > 0) && Settings.TaskDeviceEnabled[TaskIndex]) {
|
|
ttl_json = taskInterval;
|
|
|
|
if (ttl_json < lowest_ttl_json) {
|
|
lowest_ttl_json = ttl_json;
|
|
}
|
|
}
|
|
addHtml(F("\"TaskValues\": [\n"));
|
|
|
|
for (byte x = 0; x < Device[DeviceIndex].ValueCount; x++)
|
|
{
|
|
addHtml("{");
|
|
stream_next_json_object_value(F("ValueNumber"), String(x + 1));
|
|
stream_next_json_object_value(F("Name"), String(ExtraTaskSettings.TaskDeviceValueNames[x]));
|
|
stream_next_json_object_value(F("NrDecimals"), String(ExtraTaskSettings.TaskDeviceValueDecimals[x]));
|
|
stream_last_json_object_value(F("Value"), formatUserVarNoCheck(TaskIndex, x));
|
|
|
|
if (x < (Device[DeviceIndex].ValueCount - 1)) {
|
|
addHtml(F(",\n"));
|
|
}
|
|
}
|
|
addHtml(F("],\n"));
|
|
}
|
|
|
|
if (showSpecificTask) {
|
|
stream_next_json_object_value(F("TTL"), String(ttl_json * 1000));
|
|
}
|
|
|
|
if (showDataAcquisition) {
|
|
addHtml(F("\"DataAcquisition\": [\n"));
|
|
|
|
for (controllerIndex_t x = 0; x < CONTROLLER_MAX; x++)
|
|
{
|
|
addHtml("{");
|
|
stream_next_json_object_value(F("Controller"), String(x + 1));
|
|
stream_next_json_object_value(F("IDX"), String(Settings.TaskDeviceID[x][TaskIndex]));
|
|
stream_last_json_object_value(F("Enabled"), jsonBool(Settings.TaskDeviceSendData[x][TaskIndex]));
|
|
|
|
if (x < (CONTROLLER_MAX - 1)) {
|
|
addHtml(F(",\n"));
|
|
}
|
|
}
|
|
addHtml(F("],\n"));
|
|
}
|
|
|
|
if (showTaskDetails) {
|
|
stream_next_json_object_value(F("TaskInterval"), String(taskInterval));
|
|
stream_next_json_object_value(F("Type"), getPluginNameFromDeviceIndex(DeviceIndex));
|
|
stream_next_json_object_value(F("TaskName"), String(ExtraTaskSettings.TaskDeviceName));
|
|
stream_next_json_object_value(F("TaskDeviceNumber"), String(Settings.TaskDeviceNumber[TaskIndex]));
|
|
}
|
|
stream_next_json_object_value(F("TaskEnabled"), jsonBool(Settings.TaskDeviceEnabled[TaskIndex]));
|
|
stream_last_json_object_value(F("TaskNumber"), String(TaskIndex + 1));
|
|
|
|
if (TaskIndex != lastActiveTaskIndex) {
|
|
addHtml(",");
|
|
}
|
|
addHtml("\n");
|
|
}
|
|
}
|
|
|
|
if (!showSpecificTask) {
|
|
addHtml(F("],\n"));
|
|
stream_last_json_object_value(F("TTL"), String(lowest_ttl_json * 1000));
|
|
}
|
|
|
|
TXBuffer.endStream();
|
|
}
|
|
|
|
// ********************************************************************************
|
|
// JSON formatted timing statistics
|
|
// ********************************************************************************
|
|
|
|
#ifdef WEBSERVER_NEW_UI
|
|
void handle_timingstats_json() {
|
|
TXBuffer.startJsonStream();
|
|
json_init();
|
|
json_open();
|
|
# ifdef USES_TIMING_STATS
|
|
jsonStatistics(false);
|
|
# endif // ifdef USES_TIMING_STATS
|
|
json_close();
|
|
TXBuffer.endStream();
|
|
}
|
|
|
|
#endif // WEBSERVER_NEW_UI
|
|
|
|
#ifdef WEBSERVER_NEW_UI
|
|
void handle_nodes_list_json() {
|
|
if (!isLoggedIn()) { return; }
|
|
TXBuffer.startJsonStream();
|
|
json_init();
|
|
json_open(true);
|
|
|
|
for (NodesMap::iterator it = Nodes.begin(); it != Nodes.end(); ++it)
|
|
{
|
|
if (it->second.ip[0] != 0)
|
|
{
|
|
json_open();
|
|
bool isThisUnit = it->first == Settings.Unit;
|
|
|
|
if (isThisUnit) {
|
|
json_number(F("thisunit"), String(1));
|
|
}
|
|
|
|
json_number(F("first"), String(it->first));
|
|
json_prop(F("name"), isThisUnit ? Settings.Name : it->second.nodeName);
|
|
|
|
if (it->second.build) { json_prop(F("build"), String(it->second.build)); }
|
|
json_prop(F("type"), getNodeTypeDisplayString(it->second.nodeType));
|
|
json_prop(F("ip"), it->second.ip.toString());
|
|
json_number(F("age"), String(it->second.age));
|
|
json_close();
|
|
}
|
|
}
|
|
json_close(true);
|
|
TXBuffer.endStream();
|
|
}
|
|
|
|
void handle_buildinfo() {
|
|
if (!isLoggedIn()) { return; }
|
|
TXBuffer.startJsonStream();
|
|
json_init();
|
|
json_open();
|
|
{
|
|
json_open(true, F("plugins"));
|
|
|
|
for (deviceIndex_t x = 0; x <= deviceCount; x++) {
|
|
if (validPluginID(DeviceIndex_to_Plugin_id[x])) {
|
|
json_open();
|
|
json_number(F("id"), String(DeviceIndex_to_Plugin_id[x]));
|
|
json_prop(F("name"), getPluginNameFromDeviceIndex(x));
|
|
json_close();
|
|
}
|
|
}
|
|
json_close(true);
|
|
}
|
|
{
|
|
json_open(true, F("controllers"));
|
|
|
|
for (protocolIndex_t x = 0; x < CPLUGIN_MAX; x++) {
|
|
if (getCPluginID_from_ProtocolIndex(x) != INVALID_C_PLUGIN_ID) {
|
|
json_open();
|
|
json_number(F("id"), String(x + 1));
|
|
json_prop(F("name"), getCPluginNameFromProtocolIndex(x));
|
|
json_close();
|
|
}
|
|
}
|
|
json_close(true);
|
|
}
|
|
{
|
|
json_open(true, F("notifications"));
|
|
|
|
for (byte x = 0; x < NPLUGIN_MAX; x++) {
|
|
if (validNPluginID(NPlugin_id[x])) {
|
|
json_open();
|
|
json_number(F("id"), String(x + 1));
|
|
json_prop(F("name"), getNPluginNameFromNotifierIndex(x));
|
|
json_close();
|
|
}
|
|
}
|
|
json_close(true);
|
|
}
|
|
json_prop(LabelType::BUILD_DESC);
|
|
json_prop(LabelType::GIT_BUILD);
|
|
json_prop(LabelType::SYSTEM_LIBRARIES);
|
|
json_prop(LabelType::PLUGIN_COUNT);
|
|
json_prop(LabelType::PLUGIN_DESCRIPTION);
|
|
json_close();
|
|
TXBuffer.endStream();
|
|
}
|
|
|
|
#endif // WEBSERVER_NEW_UI
|
|
|
|
|
|
/*********************************************************************************************\
|
|
Streaming versions directly to TXBuffer
|
|
\*********************************************************************************************/
|
|
void stream_to_json_value(const String& value) {
|
|
if ((value.length() == 0) || !isFloat(value)) {
|
|
String html;
|
|
html.reserve(value.length() + 2);
|
|
html += '\"';
|
|
html += value;
|
|
html += '\"';
|
|
addHtml(html);
|
|
} else {
|
|
addHtml(value);
|
|
}
|
|
}
|
|
|
|
void stream_to_json_object_value(const String& object, const String& value) {
|
|
String html;
|
|
|
|
html.reserve(object.length() + 4);
|
|
|
|
html += '\"';
|
|
html += object;
|
|
html += "\":";
|
|
addHtml(html);
|
|
stream_to_json_value(value);
|
|
}
|
|
|
|
String jsonBool(bool value) {
|
|
return boolToString(value);
|
|
}
|
|
|
|
// Add JSON formatted data directly to the TXbuffer, including a trailing comma.
|
|
void stream_next_json_object_value(const String& object, const String& value) {
|
|
addHtml(to_json_object_value(object, value));
|
|
addHtml(F(",\n"));
|
|
}
|
|
|
|
// Add JSON formatted data directly to the TXbuffer, including a closing '}'
|
|
void stream_last_json_object_value(const String& object, const String& value) {
|
|
addHtml(to_json_object_value(object, value));
|
|
addHtml(F("\n}"));
|
|
}
|
|
|
|
void stream_next_json_object_value(LabelType::Enum label) {
|
|
stream_next_json_object_value(getLabel(label), getValue(label));
|
|
}
|
|
|
|
void stream_last_json_object_value(LabelType::Enum label) {
|
|
stream_last_json_object_value(getLabel(label), getValue(label));
|
|
}
|