Merge pull request #5656 from TD-er/build/use_cpp_static_functiondecl

[Build] Reduce build size using static functions
This commit is contained in:
TD-er authored and GitHub committed 2026-10-18 23:50:55 +02:00
commit 2164531742
131 files changed
+7564 -7784

No files matched your search

+6
View File
@@ -231,6 +231,7 @@ build_flags = -DESP32_STAGE
-include "esp32x_fixes.h"
-DUPDATE_NOCRYPT
-Os
; -finline-functions-called-once
; -Wnull-dereference
-DNO_GLOBAL_ESP_NOW
-DNO_GLOBAL_EEPROM
@@ -246,6 +247,11 @@ build_flags = -DESP32_STAGE
-mstrict-align
-DUSE_WEBCLIENT_HTTPS
-DFEATURE_TLS=1
; use of ROM SHA routines is automatically disabled for IDF version earlier v5.5.4
;-DUSE_SHA_ROM
;for TLS we can afford compiling for 4K RSA keys
-DUSE_4K_RSA
-DARDUINO_LOOP_STACK_SIZE=12288
lib_ignore = BLE
Zigbee
@@ -33,7 +33,7 @@
namespace ESPEasy {
namespace net {
ESPEasy_key_value_store_import_export::LabelStringFunction getLabelFnc(ESPEasy::net::nwpluginID_t nwpluginID)
static ESPEasy_key_value_store_import_export::LabelStringFunction getLabelFnc(ESPEasy::net::nwpluginID_t nwpluginID)
{
switch (nwpluginID.value)
@@ -67,7 +67,7 @@ ESPEasy_key_value_store_import_export::LabelStringFunction getLabelFnc(ESPEasy::
return nullptr;
}
ESPEasy_key_value_store_import_export::NextKeyFunction getNextKeyFnc(ESPEasy::net::nwpluginID_t nwpluginID, bool includeCredentials)
static ESPEasy_key_value_store_import_export::NextKeyFunction getNextKeyFnc(ESPEasy::net::nwpluginID_t nwpluginID, bool includeCredentials)
{
switch (nwpluginID.value)
@@ -13,7 +13,7 @@ namespace net {
/*********************************************************************************************\
* Functions to load and store network settings on the web page.
\*********************************************************************************************/
const __FlashStringHelper* toString(NetworkSettingsStruct::VarType parameterIdx, bool displayName)
static const __FlashStringHelper* toString(NetworkSettingsStruct::VarType parameterIdx, bool displayName)
{
switch (parameterIdx)
{
@@ -61,16 +61,16 @@ String getNetworkParameterName(networkDriverIndex_t NetworkDriverIndex
return name;
}
String getNetworkParameterInternalName(networkDriverIndex_t NetworkDriverIndex, NetworkSettingsStruct::VarType parameterIdx) {
static String getNetworkParameterInternalName(networkDriverIndex_t NetworkDriverIndex, NetworkSettingsStruct::VarType parameterIdx) {
bool isAlternative; // Dummy, not needed for internal name
bool displayName = false;
return getNetworkParameterName(NetworkDriverIndex, parameterIdx, displayName, isAlternative);
}
String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex,
NetworkSettingsStruct::VarType parameterIdx,
bool & isAlternative) {
static String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex,
NetworkSettingsStruct::VarType parameterIdx,
bool & isAlternative) {
bool displayName = true;
return getNetworkParameterName(NetworkDriverIndex, parameterIdx, displayName, isAlternative);
@@ -91,21 +91,22 @@ void addNetworkEnabledForm(networkIndex_t networkindex) {
addFormCheckBox(displayName, internalName, Settings.getNetworkEnabled(networkindex));
}
void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
/*
void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
networkIndex_t networkindex,
NetworkSettingsStruct::VarType varType) {
networkDriverIndex_t NetworkDriverIndex = getNetworkDriverIndex_from_NetworkIndex(networkindex);
networkDriverIndex_t NetworkDriverIndex = getNetworkDriverIndex_from_NetworkIndex(networkindex);
if (!validNetworkDriverIndex(NetworkDriverIndex)) {
if (!validNetworkDriverIndex(NetworkDriverIndex)) {
return;
}
}
bool isAlternativeDisplayName = false;
const String displayName = getNetworkParameterDisplayName(NetworkDriverIndex, varType, isAlternativeDisplayName);
const String internalName = getNetworkParameterInternalName(NetworkDriverIndex, varType);
bool isAlternativeDisplayName = false;
const String displayName = getNetworkParameterDisplayName(NetworkDriverIndex, varType, isAlternativeDisplayName);
const String internalName = getNetworkParameterInternalName(NetworkDriverIndex, varType);
switch (varType)
{
switch (varType)
{
case NetworkSettingsStruct::NETWORK_IP:
{
addFormIPBox(displayName, internalName, NetworkSettings.IP);
@@ -119,33 +120,32 @@ void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
case NetworkSettingsStruct::NETWORK_USER:
{
/*
const size_t fieldMaxLength =
NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_USER_LENGTH : sizeof(SecuritySettings.NetworkUser[0]) - 1;
addFormTextBox(displayName,
internalName,
getNetworkUser(networkindex, NetworkSettings, false),
fieldMaxLength);
*/
break;
// const size_t fieldMaxLength =
// NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_USER_LENGTH : sizeof(SecuritySettings.NetworkUser[0]) - 1;
// addFormTextBox(displayName,
// internalName,
// getNetworkUser(networkindex, NetworkSettings, false),
// fieldMaxLength);
break;
}
case NetworkSettingsStruct::NETWORK_PASS:
{
/*
const size_t fieldMaxLength =
NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_PASS_LENGTH : sizeof(SecuritySettings.NetworkPassword[0]) - 1;
if (isAlternativeDisplayName) {
// const size_t fieldMaxLength =
// NetworkSettings.useExtendedCredentials() ? EXT_SECURITY_MAX_PASS_LENGTH : sizeof(SecuritySettings.NetworkPassword[0]) - 1;
// if (isAlternativeDisplayName) {
// It is not a regular password, thus use normal text field.
addFormTextBox(displayName, internalName,
getNetworkPass(networkindex, NetworkSettings),
fieldMaxLength);
} else {
addFormPasswordBox(displayName, internalName,
getNetworkPass(networkindex, NetworkSettings),
fieldMaxLength);
}
*/
// addFormTextBox(displayName, internalName,
// getNetworkPass(networkindex, NetworkSettings),
// fieldMaxLength);
// } else {
// addFormPasswordBox(displayName, internalName,
// getNetworkPass(networkindex, NetworkSettings),
// fieldMaxLength);
// }
break;
}
@@ -157,9 +157,9 @@ void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
case NetworkSettingsStruct::NETWORK_ENABLED:
addFormCheckBox(displayName, internalName, Settings.getNetworkEnabled(networkindex));
break;
}
}
}
}
*/
void saveNetworkParameterForm(NetworkSettingsStruct & NetworkSettings,
networkIndex_t networkindex,
NetworkSettingsStruct::VarType varType) {
@@ -19,19 +19,15 @@ String getNetworkParameterName(networkDriverIndex_t NetworkDriverIndex
bool displayName,
bool & isAlternative);
String getNetworkParameterInternalName(networkDriverIndex_t NetworkDriverIndex,
NetworkSettingsStruct::VarType parameterIdx);
String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex,
NetworkSettingsStruct::VarType parameterIdx,
bool & isAlternative);
void addNetworkEnabledForm(networkIndex_t networkindex);
/*
void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
networkIndex_t networkindex,
NetworkSettingsStruct::VarType varType);
*/
void saveNetworkParameterForm(NetworkSettingsStruct & NetworkSettings,
networkIndex_t networkindex,
NetworkSettingsStruct::VarType varType);
+1 -1
View File
@@ -14,7 +14,7 @@
//#include "../../ESPEasy_fdwdecl.h"
controllerIndex_t firstEnabledBlynk_ControllerIndex() {
static controllerIndex_t firstEnabledBlynk_ControllerIndex() {
for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) {
protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(i);
-1
View File
@@ -8,7 +8,6 @@
#include "../DataTypes/ControllerIndex.h"
controllerIndex_t firstEnabledBlynk_ControllerIndex();
// FIXME: this should go to PLUGIN_WRITE in _C012.ino
const __FlashStringHelper * Command_Blynk_Get(struct EventStruct *event,
+1 -1
View File
@@ -12,7 +12,7 @@
#include "../Helpers/Misc.h"
// controllerIndex = (event->Par1 - 1); Par1 is here for 1 ... CONTROLLER_MAX
bool validControllerVar(struct EventStruct *event, controllerIndex_t& controllerIndex)
static bool validControllerVar(struct EventStruct *event, controllerIndex_t& controllerIndex)
{
if (event->Par1 <= 0) { return false; }
controllerIndex = static_cast<controllerIndex_t>(event->Par1 - 1);
+16 -16
View File
@@ -27,33 +27,33 @@
// Normally those would be declared in the .h file as private members
// But since these are not part of a class, forward declare them in the .cpp
//void createAndSetPortStatus_Mode_State(uint32_t key, uint8_t newMode, int8_t newState);
const __FlashStringHelper * getPluginIDAndPrefix(char selection, pluginID_t& pluginID, bool& success);
void logErrorGpioOffline(const __FlashStringHelper * prefix, int port);
void logErrorGpioOutOfRange(const __FlashStringHelper * prefix, int port, const char* Line = nullptr);
void logErrorGpioNotOutput(const __FlashStringHelper * prefix, int port);
void logErrorModeOutOfRange(const __FlashStringHelper * prefix, int port);
bool gpio_monitor_helper(int port, struct EventStruct *event, const char* Line);
bool gpio_unmonitor_helper(int port, struct EventStruct *event, const char* Line);
static const __FlashStringHelper * getPluginIDAndPrefix(char selection, pluginID_t& pluginID, bool& success);
static void logErrorGpioOffline(const __FlashStringHelper * prefix, int port);
static void logErrorGpioOutOfRange(const __FlashStringHelper * prefix, int port, const char* Line = nullptr);
static void logErrorGpioNotOutput(const __FlashStringHelper * prefix, int port);
static void logErrorModeOutOfRange(const __FlashStringHelper * prefix, int port);
static bool gpio_monitor_helper(int port, struct EventStruct *event, const char* Line);
static bool gpio_unmonitor_helper(int port, struct EventStruct *event, const char* Line);
#ifdef USES_P009
bool mcpgpio_range_pattern_helper(struct EventStruct *event, const char* Line, bool isWritePattern);
static bool mcpgpio_range_pattern_helper(struct EventStruct *event, const char* Line, bool isWritePattern);
#endif
#ifdef USES_P019
bool pcfgpio_range_pattern_helper(struct EventStruct *event, const char* Line, bool isWritePattern);
static bool pcfgpio_range_pattern_helper(struct EventStruct *event, const char* Line, bool isWritePattern);
#endif
bool gpio_mode_range_helper(uint8_t pin, uint8_t pinMode, struct EventStruct *event, const char* Line);
static bool gpio_mode_range_helper(uint8_t pin, uint8_t pinMode, struct EventStruct *event, const char* Line);
#ifdef USES_P019
uint8_t getPcfAddress(uint8_t pin);
static uint8_t getPcfAddress(uint8_t pin);
#endif
bool setGPIOMode(uint8_t pin, uint8_t mode);
static bool setGPIOMode(uint8_t pin, uint8_t mode);
#ifdef USES_P019
bool setPCFMode(uint8_t pin, uint8_t mode);
static bool setPCFMode(uint8_t pin, uint8_t mode);
#endif
#ifdef USES_P009
bool setMCPMode(uint8_t pin, uint8_t mode);
bool mcpgpio_plugin_range_helper(uint8_t pin1, uint8_t pin2, uint16_t &result);
static bool setMCPMode(uint8_t pin, uint8_t mode);
static bool mcpgpio_plugin_range_helper(uint8_t pin1, uint8_t pin2, uint16_t &result);
#endif
#ifdef USES_P019
bool pcfgpio_plugin_range_helper(uint8_t pin1, uint8_t pin2, uint16_t &result);
static bool pcfgpio_plugin_range_helper(uint8_t pin1, uint8_t pin2, uint16_t &result);
#endif
+1 -1
View File
@@ -17,7 +17,7 @@
#endif // if FEATURE_JSON_EVENT
#if FEATURE_SEND_TO_HTTP || FEATURE_POST_TO_HTTP || FEATURE_PUT_TO_HTTP
const __FlashStringHelper* httpEmitToHTTP(struct EventStruct *event,
static const __FlashStringHelper* httpEmitToHTTP(struct EventStruct *event,
const __FlashStringHelper *logIdentifier,
const __FlashStringHelper *HttpMethod,
const char *Line,
-11
View File
@@ -3,17 +3,6 @@
#include "../../ESPEasy_common.h"
#if FEATURE_SEND_TO_HTTP || FEATURE_POST_TO_HTTP || FEATURE_PUT_TO_HTTP
const __FlashStringHelper* httpEmitToHTTP(struct EventStruct *event,
const __FlashStringHelper *logIdentifier,
const __FlashStringHelper *HttpMethod,
const char *Line,
const int timeout,
const bool waitForAck,
const bool useHeader,
const bool useBody,
const bool useHttps);
#endif // if FEATURE_SEND_TO_HTTP || FEATURE_POST_TO_HTTP || FEATURE_PUT_TO_HTTP
#if FEATURE_SEND_TO_HTTP
const __FlashStringHelper* Command_HTTP_SendToHTTP(struct EventStruct *event,
const char *Line);
+3 -3
View File
@@ -62,7 +62,7 @@
#include "../Helpers/StringConverter.h"
bool checkNrArguments(const char *cmd, const String& Line, int nrArguments) {
static bool checkNrArguments(const char *cmd, const String& Line, int nrArguments) {
if (nrArguments < 0) { return true; }
// 0 arguments means argument on pos1 is valid (the command) and argpos 2 should not be there.
@@ -129,7 +129,7 @@ bool checkNrArguments(const char *cmd, const String& Line, int nrArguments) {
return true;
}
bool checkSourceFlags(EventValueSource::Enum source, EventValueSourceGroup::Enum group) {
static bool checkSourceFlags(EventValueSource::Enum source, EventValueSourceGroup::Enum group) {
if (EventValueSource::partOfGroup(source, group)) {
return true;
}
@@ -174,7 +174,7 @@ bool InternalCommands::do_command_case_all_restricted(command_function pFunc,
return do_command_case(_data, pFunc, nrArguments, EventValueSourceGroup::Enum::RESTRICTED);
}
bool do_command_case_check(command_case_data & data,
static bool do_command_case_check(command_case_data & data,
int nrArguments,
EventValueSourceGroup::Enum group)
{
@@ -326,7 +326,7 @@ const char Internal_commands_w[] PROGMEM =
;
#endif
const char* getInternalCommand_Haystack_Offset(const char firstLetter, int& offset)
static const char* getInternalCommand_Haystack_Offset(const char firstLetter, int& offset)
{
const char *haystack = nullptr;
+1 -1
View File
@@ -20,7 +20,7 @@
#endif
// networkIndex = (event->Par1 - 1); Par1 is here for 1 ... NETWORK_MAX
bool validNetworkVar(struct EventStruct *event, ESPEasy::net::networkIndex_t& networkIndex)
static bool validNetworkVar(struct EventStruct *event, ESPEasy::net::networkIndex_t& networkIndex)
{
if (event->Par1 <= 0) { return false; }
networkIndex = static_cast<ESPEasy::net::networkIndex_t>(event->Par1 - 1);
+1 -1
View File
@@ -12,7 +12,7 @@
# include <SD.h>
void printDirectory(fs::File dir, int numTabs)
static void printDirectory(fs::File dir, int numTabs)
{
while (true) {
fs::File entry = dir.openNextFile();
-2
View File
@@ -6,8 +6,6 @@
# include <FS.h>
void printDirectory(fs::File dir,
int numTabs);
const __FlashStringHelper* Command_SD_LS(struct EventStruct *event,
const char *Line);
String Command_SD_Remove(struct EventStruct *event,
+20 -20
View File
@@ -22,7 +22,7 @@
#include "../Helpers/StringParser.h"
// taskIndex = (event->Par1 - 1); Par1 is here for 1 ... TASKS_MAX
bool validTaskIndexVar(struct EventStruct *event, taskIndex_t& taskIndex)
static bool validTaskIndexVar(struct EventStruct *event, taskIndex_t& taskIndex)
{
if (event == nullptr) { return false; }
@@ -38,7 +38,7 @@ bool validTaskIndexVar(struct EventStruct *event, taskIndex_t& taskIndex)
// taskIndex = (event->Par1 - 1); Par1 is here for 1 ... TASKS_MAX
// varNr = event->Par2 - 1;
bool validTaskVars(struct EventStruct *event, taskIndex_t& taskIndex, unsigned int& varNr)
static bool validTaskVars(struct EventStruct *event, taskIndex_t& taskIndex, unsigned int& varNr)
{
if (event == nullptr) { return false; }
@@ -56,7 +56,7 @@ bool validTaskVars(struct EventStruct *event, taskIndex_t& taskIndex, unsigned i
return false;
}
bool validateAndParseTaskIndexArguments(struct EventStruct * event, const char *Line, taskIndex_t &taskIndex)
static bool validateAndParseTaskIndexArguments(struct EventStruct * event, const char *Line, taskIndex_t &taskIndex)
{
if (!validTaskIndexVar(event, taskIndex)) {
String taskName;
@@ -75,7 +75,7 @@ bool validateAndParseTaskIndexArguments(struct EventStruct * event, const char *
/**
* parse TaskName/TaskValue when not numeric for task name and value name and validate values
*/
bool validateAndParseTaskValueArguments(struct EventStruct * event, const char *Line, taskIndex_t &taskIndex, unsigned int &varNr)
static bool validateAndParseTaskValueArguments(struct EventStruct * event, const char *Line, taskIndex_t &taskIndex, unsigned int &varNr)
{
if (!validTaskVars(event, taskIndex, varNr) || (event->Par2 <= 0 || event->Par2 >= VARS_PER_TASK)) // Extra check required because of shortcutting in validTaskVars()
{
@@ -101,7 +101,7 @@ bool validateAndParseTaskValueArguments(struct EventStruct * event, const char *
return true;
}
const __FlashStringHelper * taskValueSet(struct EventStruct *event, const char *Line, taskIndex_t& taskIndex, bool& success)
static const __FlashStringHelper * taskValueSet(struct EventStruct *event, const char *Line, taskIndex_t& taskIndex, bool& success)
{
String TmpStr1;
unsigned int varNr;
@@ -198,7 +198,7 @@ const __FlashStringHelper * Command_Task_ClearAll(struct EventStruct *event, con
return return_command_success_flashstr();
}
const __FlashStringHelper * Command_Task_EnableDisable(struct EventStruct *event, bool enable, const char *Line)
static const __FlashStringHelper * Command_Task_EnableDisable(struct EventStruct *event, bool enable, const char *Line)
{
taskIndex_t taskIndex;
if (validateAndParseTaskIndexArguments(event, Line, taskIndex)) {
@@ -216,7 +216,7 @@ const __FlashStringHelper * Command_Task_EnableDisable(struct EventStruct *event
}
#if FEATURE_PLUGIN_PRIORITY
const __FlashStringHelper * Command_PriorityTask_DisableTask(struct EventStruct *event, const char *Line)
static const __FlashStringHelper * Command_PriorityTask_DisableTask(struct EventStruct *event, const char *Line)
{
taskIndex_t taskIndex;
@@ -262,22 +262,11 @@ const __FlashStringHelper * Command_Task_ValueSet(struct EventStruct *event, con
}
#if FEATURE_STRING_VARIABLES
const __FlashStringHelper * Command_Task_ValueSetDerived(struct EventStruct *event, const char *Line)
{
return taskValueSetString(event, Line, F(TASK_VALUE_DERIVED_PREFIX_TEMPLATE), F(TASK_VALUE_UOM_PREFIX_TEMPLATE), F(TASK_VALUE_VTYPE_PREFIX_TEMPLATE));
}
const __FlashStringHelper * Command_Task_ValueSetPresentation(struct EventStruct *event, const char *Line)
{
return taskValueSetString(event, Line, F(TASK_VALUE_PRESENTATION_PREFIX_TEMPLATE));
}
const __FlashStringHelper * taskValueSetString(struct EventStruct *event, const char *Line, const __FlashStringHelper * storageTemplate, const __FlashStringHelper * uomTemplate, const __FlashStringHelper * vTypeTemplate)
static const __FlashStringHelper * taskValueSetString(struct EventStruct *event, const char *Line, const __FlashStringHelper * storageTemplate, const __FlashStringHelper * uomTemplate, const __FlashStringHelper * vTypeTemplate)
{
String taskName;
taskIndex_t tmpTaskIndex = INVALID_TASK_INDEX;
if ((event->Par1 <= 0 || event->Par1 >= INVALID_TASK_INDEX) && GetArgv(Line, taskName, 2)) {
tmpTaskIndex = findTaskIndexByName(taskName, true);
const taskIndex_t tmpTaskIndex = findTaskIndexByName(taskName, true);
if (tmpTaskIndex != INVALID_TASK_INDEX) {
event->Par1 = tmpTaskIndex + 1;
}
@@ -364,6 +353,17 @@ const __FlashStringHelper * taskValueSetString(struct EventStruct *event, const
}
return return_command_failed_flashstr(); // taskValueSet(event, Line, taskIndex, success);
}
const __FlashStringHelper * Command_Task_ValueSetDerived(struct EventStruct *event, const char *Line)
{
return taskValueSetString(event, Line, F(TASK_VALUE_DERIVED_PREFIX_TEMPLATE), F(TASK_VALUE_UOM_PREFIX_TEMPLATE), F(TASK_VALUE_VTYPE_PREFIX_TEMPLATE));
}
const __FlashStringHelper * Command_Task_ValueSetPresentation(struct EventStruct *event, const char *Line)
{
return taskValueSetString(event, Line, F(TASK_VALUE_PRESENTATION_PREFIX_TEMPLATE), nullptr, nullptr);
}
#endif
const __FlashStringHelper * Command_Task_ValueToggle(struct EventStruct *event, const char *Line)
-5
View File
@@ -23,11 +23,6 @@ const __FlashStringHelper* Command_Task_ValueSetDerived(struct EventStruct *even
const char *Line);
const __FlashStringHelper* Command_Task_ValueSetPresentation(struct EventStruct *event,
const char *Line);
const __FlashStringHelper* taskValueSetString(struct EventStruct *event,
const char *Line,
const __FlashStringHelper *storageTemplate,
const __FlashStringHelper *uomTemplate = nullptr,
const __FlashStringHelper *vTypeTemplate = nullptr);
#endif // if FEATURE_STRING_VARIABLES
const __FlashStringHelper* Command_Task_ValueToggle(struct EventStruct *event,
const char *Line);
+1 -1
View File
@@ -10,7 +10,7 @@
#include "../Helpers/Misc.h"
#include "../Helpers/Scheduler.h"
const __FlashStringHelper * command_setRulesTimer(int msecFromNow, int timerIndex, int recurringCount, bool startImmediately = false) {
static const __FlashStringHelper * command_setRulesTimer(int msecFromNow, int timerIndex, int recurringCount, bool startImmediately = false) {
if (msecFromNow < 0)
{
addLog(LOG_LEVEL_ERROR, F("TIMER: time must be positive"));
+1 -1
View File
@@ -13,7 +13,7 @@
#include <Wire.h>
void i2c_scanI2Cbus(bool dbg, int8_t channel, uint8_t i2cBus) {
static void i2c_scanI2Cbus(bool dbg, int8_t channel, uint8_t i2cBus) {
uint8_t error, address;
#if FEATURE_I2CMULTIPLEXER
-4
View File
@@ -3,10 +3,6 @@
#include "../../ESPEasy_common.h"
#if FEATURE_I2C
void i2c_scanI2Cbus(bool dbg,
int8_t channel,
uint8_t i2cBus);
const __FlashStringHelper* Command_i2c_Scanner(struct EventStruct *event,
const char *Line);
#endif
@@ -2,7 +2,7 @@
#if FEATURE_PACKED_RAW_DATA
uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset) {
static uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset) {
offset = 0;
factor = 1;
if (dtype > 0x1000 && dtype < 0x12FF) {
@@ -35,7 +35,7 @@ uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offse
return 0;
}
void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor) {
static void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor) {
// Clip values to upper limit
const uint64_t upperlimit = (1ull << (8*byteSize)) - 1;
if (value > upperlimit) { value = upperlimit; }
@@ -49,7 +49,7 @@ void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, uint8_t *data, uint8_t&
}
}
void LoRa_intToBytes(int64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor) {
static void LoRa_intToBytes(int64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor) {
// Clip values to lower limit
const int64_t lowerlimit = (1ull << ((8*byteSize) - 1)) * -1;
if (value < lowerlimit) { value = lowerlimit; }
@@ -59,7 +59,7 @@ void LoRa_intToBytes(int64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cu
LoRa_uintToBytes(value, byteSize, data, cursor);
}
String LoRa_base16Encode(uint8_t *data, size_t size) {
static String LoRa_base16Encode(uint8_t *data, size_t size) {
String output;
output.reserve(size * 2);
char buffer[3];
@@ -69,13 +69,13 @@ typedef uint32_t PackedData_enum;
#define PackedData_vcc 5
#define PackedData_pct_8 6
uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset);
//uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset);
void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor);
//void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor);
void LoRa_intToBytes(int64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor);
//void LoRa_intToBytes(int64_t value, uint8_t byteSize, uint8_t *data, uint8_t& cursor);
String LoRa_base16Encode(uint8_t *data, size_t size);
//String LoRa_base16Encode(uint8_t *data, size_t size);
String LoRa_addInt(uint64_t value, PackedData_enum datatype);
+4 -4
View File
@@ -97,7 +97,7 @@ const __FlashStringHelper* getPluginFunctionName(int function) {
return F("Unknown");
}
bool mustLogFunction(int function) {
static bool mustLogFunction(int function) {
if (!Settings.EnableTimingStats()) { return false; }
switch (function) {
@@ -170,7 +170,7 @@ const __FlashStringHelper* getCPluginCFunctionName(CPlugin::Function function) {
return F("Unknown");
}
bool mustLogCFunction(CPlugin::Function function) {
static bool mustLogCFunction(CPlugin::Function function) {
if (!Settings.EnableTimingStats()) { return false; }
switch (function) {
@@ -205,14 +205,14 @@ bool mustLogCFunction(CPlugin::Function function) {
return false;
}
bool mustLogNWFunction(NWPlugin::Function function)
static bool mustLogNWFunction(NWPlugin::Function function)
{
return Settings.EnableTimingStats();
}
// Return flash string type to reduce bin size
const __FlashStringHelper* getMiscStatsName_F(TimingStatsElements stat) {
static const __FlashStringHelper* getMiscStatsName_F(TimingStatsElements stat) {
switch (stat) {
case TimingStatsElements::LOADFILE_STATS: return F("Load File");
case TimingStatsElements::SAVEFILE_STATS: return F("Save File");
+3 -3
View File
@@ -180,10 +180,10 @@ private:
const __FlashStringHelper* getPluginFunctionName(int function);
bool mustLogFunction(int function);
//bool mustLogFunction(int function);
const __FlashStringHelper* getCPluginCFunctionName(CPlugin::Function function);
bool mustLogCFunction(CPlugin::Function function);
bool mustLogNWFunction(NWPlugin::Function function);
//bool mustLogCFunction(CPlugin::Function function);
//bool mustLogNWFunction(NWPlugin::Function function);
String getMiscStatsName(TimingStatsElements stat);
void stopTimerTask(deviceIndex_t T,
+1 -1
View File
@@ -1,6 +1,6 @@
#include "../DataTypes/IntendedRebootReason.h"
const __FlashStringHelper * toString_f(IntendedRebootReason_e reason) {
static const __FlashStringHelper * toString_f(IntendedRebootReason_e reason) {
switch (reason) {
case IntendedRebootReason_e::DeepSleep: return F("DeepSleep");
case IntendedRebootReason_e::DelayedReboot: return F("DelayedReboot");
+1 -1
View File
@@ -17,7 +17,7 @@ constexpr int logLevels[] =
};
// We can't have a globally declared flash string array on ESP8266, so need to wrap it in a function.
const __FlashStringHelper* getLogLevelDisplayStringFromIndex(uint8_t index)
static const __FlashStringHelper* getLogLevelDisplayStringFromIndex(uint8_t index)
{
const __FlashStringHelper *logLevelDisplayStrings[]
{
+25 -7
View File
@@ -2,13 +2,24 @@
#include "../Helpers/StringConverter.h"
String toNodeTypeDisplayString(uint8_t nodeType) {
const __FlashStringHelper* suffix = F("");
static const __FlashStringHelper* toNodeTypeDisplayFlashString(uint8_t nodeType)
{
switch (nodeType)
{
case NODE_TYPE_ID_ESP_EASY_STD: return F("ESP Easy");
case NODE_TYPE_ID_ESP_EASYM_STD: return F("ESP Easy Mega");
case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy");
case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy");
case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy");
default:
return F("");
}
}
static const __FlashStringHelper* toNodeType_ESP32_suffix(uint8_t nodeType) {
const __FlashStringHelper* suffix = F("");
switch (nodeType)
{
case NODE_TYPE_ID_ESP_EASY32_STD: break;
case NODE_TYPE_ID_ESP_EASY32S2_STD: suffix = F("-S2"); break;
case NODE_TYPE_ID_ESP_EASY32S3_STD: suffix = F("-S3"); break;
@@ -23,11 +34,18 @@ String toNodeTypeDisplayString(uint8_t nodeType) {
case NODE_TYPE_ID_ESP_EASY32H4_STD: suffix = F("-H4"); break;
case NODE_TYPE_ID_ESP_EASY32P4_STD: suffix = F("-P4"); break;
case NODE_TYPE_ID_ESP_EASY32P4r3_STD: suffix = F("-P4r3"); break;
case NODE_TYPE_ID_RPI_EASY_STD: return F("RPI Easy");
case NODE_TYPE_ID_ARDUINO_EASY_STD: return F("Arduino Easy");
case NODE_TYPE_ID_NANO_EASY_STD: return F("Nano Easy");
default:
return EMPTY_STRING;
return nullptr; // Not an ESP32 node type
}
return suffix;
}
String toNodeTypeDisplayString(uint8_t nodeType) {
String res(toNodeTypeDisplayFlashString(nodeType));
if (!res.isEmpty()) return res;
const __FlashStringHelper* suffix = toNodeType_ESP32_suffix(nodeType);
if (suffix == nullptr) return EMPTY_STRING;
return concat(F("ESP Easy 32"), suffix);
}
+1 -1
View File
@@ -3,7 +3,7 @@
#include "../Helpers/StringConverter.h"
#ifndef BUILD_NO_DEBUG
const __FlashStringHelper * toString_f(SchedulerIntervalTimer_e timer) {
static const __FlashStringHelper * toString_f(SchedulerIntervalTimer_e timer) {
switch (timer) {
case SchedulerIntervalTimer_e::TIMER_20MSEC: return F("TIMER_20MSEC");
case SchedulerIntervalTimer_e::TIMER_100MSEC: return F("TIMER_100MSEC");
File diff suppressed because it is too large. Load diff
+4 -77
View File
@@ -14,7 +14,7 @@
String EventToFileName(const String& eventName);
String FileNameToEvent(const String& fileName);
#endif
#endif // ifdef WEBSERVER_NEW_RULES
void checkRuleSets();
@@ -27,7 +27,7 @@ bool processNextEvent();
/********************************************************************************************\
Rules processing
\*********************************************************************************************/
void rulesProcessing(const String& event);
void rulesProcessing(const String& event);
/********************************************************************************************\
Rules processing
@@ -35,89 +35,16 @@ void rulesProcessing(const String& event);
\*********************************************************************************************/
bool rulesProcessingFile(const String& fileName,
const String& event,
size_t pos = 0,
bool startOnMatched = false);
size_t pos = 0,
bool startOnMatched = false);
/********************************************************************************************\
Parse string commands
\*********************************************************************************************/
bool get_next_inner_bracket(const String& line,
unsigned int& startIndex,
int & closingIndex,
char closingBracket);
bool get_next_argument(const String& fullCommand,
int & index,
String & argument,
char separator);
bool parse_bitwise_functions(const String& cmd_s_lower,
const String& arg1,
const String& arg2,
const String& arg3,
uint32_t & result);
bool parse_math_functions(const String& cmd_s_lower,
const String& arg1,
const String& arg2,
const String& arg3,
ESPEASY_RULES_FLOAT_TYPE & result);
void parse_string_commands(String& line);
void substitute_eventvalue(String & line,
const String& event);
void parseCompleteNonCommentLine(String& line,
const String& event,
String& action,
bool & match,
bool & codeBlock,
bool & isCommand,
bool & isOneLiner,
bool condition[],
bool ifBranche[],
uint8_t & ifBlock,
uint8_t & fakeIfBlock,
bool startOnMatched);
void processMatchedRule(String& action,
const String& event,
bool & isCommand,
bool condition[],
bool ifBranche[],
uint8_t & ifBlock,
uint8_t & fakeIfBlock);
/********************************************************************************************\
Check expression
\*********************************************************************************************/
bool conditionMatchExtended(String& check);
bool conditionMatch(const String& check);
/********************************************************************************************\
Matching time notations HH:MM:SS and HH:MM:SS and HH
\*********************************************************************************************/
void logtimeStringToSeconds(const String& tBuf,
int hours,
int minutes,
int seconds,
bool valid);
// convert old and new time string to nr of seconds
// return whether it should be considered a time string.
bool timeStringToSeconds(const String& tBuf,
int & time_seconds,
String& timeString);
/********************************************************************************************\
Generate rule events based on task refresh
\*********************************************************************************************/
+1 -1
View File
@@ -26,7 +26,7 @@
#include "../Helpers/StringConverter.h"
#include "../WebServer/ESPEasy_WebServer.h"
void updateLoopStats() {
static void updateLoopStats() {
++loopCounter;
++loopCounter_full;
+5 -38
View File
@@ -26,6 +26,7 @@
#include "../Helpers/_Plugin_init.h"
#include "../Helpers/DeepSleep.h"
#include "../Helpers/ESPEasyRTC.h"
#include "../Helpers/ESPEasy_CrashHandler.h"
#include "../Helpers/ESPEasy_FactoryDefault.h"
#include "../Helpers/ESPEasy_Storage.h"
#include "../Helpers/ESPEasy_checks.h"
@@ -117,11 +118,13 @@ void RTOS_HandleSchedule(void *parameter)
/*********************************************************************************************\
* ISR call back function for handling the watchdog.
\*********************************************************************************************/
void sw_watchdog_callback(void *arg)
/*
static void sw_watchdog_callback(void *arg)
{
yield(); // feed the WD
++sw_watchdog_callback_count;
}
*/
/*********************************************************************************************\
* SETUP
@@ -405,44 +408,8 @@ void ESPEasy_setup()
Settings.UseRTOSMultitasking = false; // For now, disable it, we experience heap corruption.
if ((RTC.bootFailedCount > 10) && (RTC.bootCounter > 10)) {
uint8_t toDisable = RTC.bootFailedCount - 10;
toDisable = disablePlugin(toDisable);
disableFailingComponent();
if (toDisable != 0) {
toDisable = disableController(toDisable);
}
#if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableNotification(toDisable);
}
#endif // if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableNetwork(toDisable);
}
if (toDisable != 0) {
toDisable = disableRules(toDisable);
}
if (toDisable != 0) {
toDisable = disableAllPlugins(toDisable);
}
if (toDisable != 0) {
toDisable = disableAllControllers(toDisable);
}
#if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableAllNotifications(toDisable);
}
#endif // if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableAllNetworkss(toDisable);
}
}
#if FEATURE_ETHERNET
// This ensures, that changing WIFI OR ETHERNET MODE happens properly only after reboot. Changing without reboot would not be a good idea.
+1 -1
View File
@@ -39,7 +39,7 @@ static bool rtttlPlaying = false;
# if FEATURE_ANYRTTTL_ASYNC
static String rtttlMelody;
void clear_rtttl_melody() {
static void clear_rtttl_melody() {
// The non-blocking play will read from a char pointer.
// So we must stop the playing before changing the string as it could otherwise lead to a crash.
if (anyrtttl::nonblocking::isPlaying()) { // If currently playing, cancel that
-1
View File
@@ -19,7 +19,6 @@ bool play_rtttl(int8_t _pin,
const char *p);
# if FEATURE_ANYRTTTL_LIB && FEATURE_ANYRTTTL_ASYNC
void update_rtttl();
void clear_rtttl_melody();
void set_rtttl_melody(String& melody);
# endif // if FEATURE_ANYRTTTL_LIB && FEATURE_ANYRTTTL_ASYNC
#endif // if FEATURE_RTTTL
+292 -276
View File
@@ -30,7 +30,11 @@
# define DALLAS_IRAM_ATTR
# endif // ifdef ESP8266
# ifdef ESP32
# define DALLAS_IRAM_ATTR IRAM_ATTR
// noinline: GCC inlines a function with a single caller into that caller.
// (e.g. Dallas_read_bit_ISR, as LTO is enabled for ESP32 builds)
// The timing critical code would then run from flash, as the caller is not in IRAM.
# define DALLAS_IRAM_ATTR IRAM_ATTR __attribute__((noinline))
# endif // ifdef ESP32
@@ -51,7 +55,7 @@ int32_t usec_release{};
int32_t presence_start{};
int32_t presence_end{};
void DALLAS_IRAM_ATTR Dallas_pinModeInput(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx)
static void DALLAS_IRAM_ATTR Dallas_pinModeInput(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx)
{
if (gpio_pin_rx == gpio_pin_tx) {
// let pin float, pull up will raise level
@@ -67,7 +71,7 @@ void DALLAS_IRAM_ATTR Dallas_pinModeInput(uint32_t gpio_pin_rx, uint32_t gpio_pi
}
}
void DALLAS_IRAM_ATTR Dallas_pinWrite(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx, bool pinstate)
static void DALLAS_IRAM_ATTR Dallas_pinWrite(uint32_t gpio_pin_rx, uint32_t gpio_pin_tx, bool pinstate)
{
DIRECT_pinWrite_ISR(gpio_pin_tx, pinstate);
@@ -136,7 +140,7 @@ int Dallas_measure_rise_time(int8_t gpio_pin_rx, int8_t gpio_pin_tx)
// References to 1-wire family codes:
// http://owfs.sourceforge.net/simple_family.html
// https://github.com/owfs/owfs-doc/wiki/1Wire-Device-List
const __FlashStringHelper* Dallas_getModel(uint8_t family, const bool hasFixedResolution) {
static const __FlashStringHelper* Dallas_getModel(uint8_t family, const bool hasFixedResolution) {
switch (family)
{
case 0x28: return F("DS18B20");
@@ -178,7 +182,7 @@ uint64_t Dallas_addr_to_uint64(const uint8_t addr[]) {
return tmpAddr_64;
}
void Dallas_uint64_to_addr(uint64_t value, uint8_t addr[]) {
static void Dallas_uint64_to_addr(uint64_t value, uint8_t addr[]) {
uint8_t i = 8;
while (i > 0) {
@@ -188,6 +192,189 @@ void Dallas_uint64_to_addr(uint64_t value, uint8_t addr[]) {
}
}
static bool Dallas_plugin(pluginID_t pluginID)
{
constexpr pluginID_t PLUGIN_ID_P004_DALLAS_TEMP(4);
constexpr pluginID_t PLUGIN_ID_P080_DALLAS_IBUTTON(80);
constexpr pluginID_t PLUGIN_ID_P100_DS2423_COUNTER(100);
return (pluginID == PLUGIN_ID_P004_DALLAS_TEMP) ||
(pluginID == PLUGIN_ID_P080_DALLAS_IBUTTON) ||
(pluginID == PLUGIN_ID_P100_DS2423_COUNTER);
}
/*********************************************************************************************\
* Dallas Read bit
\*********************************************************************************************/
static uint8_t DALLAS_IRAM_ATTR Dallas_read_bit_ISR(
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
uint32_t& start)
{
uint8_t r = 0;
ISR_noInterrupts();
Dallas_pinLow;
start = micros();
// delayMicroseconds(1);
// Make sure there is at least 5 usec 'low' level.
// Minimum state by Infineon, however other brands, like Analog,
// claim lower minimum.
while (usecPassedSince_fast(start) < 4) {}
// Set to 'input', state will be pulled high by pull-up resistor
// This will take t_RC, which is typically 2 - 3 usec.
// We have to wait upto 15 usec to see the pin be pulled up,
// otherwise it is apparently be pulled low by the sensor
Dallas_pinInput;
if (Dallas_waitForPinHigh(gpio_pin_rx, start, 15 + usec_release)) {
// Wait for max 15 usec to have a high level
r = 1;
Dallas_pinHigh;
}
ISR_interrupts();
if (r == 0) {
// Wait upto 60 usec to have a high level
// Pin should be released within 15 ... 60 usec from start of read slot.
// We must make sure we don't try to do a strong pull-up
// while the sensor is still trying to pull-down.
Dallas_waitForPinHigh(gpio_pin_rx, start, 60);
}
// Pull high again so we can support parasite mode for 1 sensor
// Sending out a high signal level is stronger than a pull-up resistor can supply
Dallas_pinHigh;
return r;
}
static uint8_t Dallas_read_bit(int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
if (gpio_pin_rx == -1) { return 0; }
if (gpio_pin_tx == -1) { return 0; }
uint32_t start;
const uint8_t r = Dallas_read_bit_ISR(gpio_pin_rx, gpio_pin_tx, start);
// Recovery time, make sure we at least wait for 10 usec + RC-rise time
delayMicroseconds(2 * usec_release + 10);
while (usecPassedSince_fast(start) < 60) {
// Allow for some
// Wait for another 45 usec
// Complete read cycle:
// LOW: 6 usec
// Float: 9 msec
// Read value. Typically the sensor keeps the level low for 27 usec.
// Wait for 55 usec => complete cycle = 6 + 9 + 55 = 70 usec.
}
return r;
}
/*********************************************************************************************\
* Dallas Write bit
\*********************************************************************************************/
static void DALLAS_IRAM_ATTR Dallas_write_bit_ISR(uint8_t v,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
int32_t low_time,
int32_t high_time,
uint32_t& start)
{
ISR_noInterrupts();
start = micros();
Dallas_pinLow;
while (usecPassedSince_fast(start) < low_time) {
// output remains low
}
start = micros();
Dallas_pinHigh;
ISR_interrupts();
}
static void Dallas_write_bit(uint8_t v, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
if (gpio_pin_tx == -1) { return; }
// Determine times in usec for high and low
// write 1: low 6 usec, high 64 usec (no less than 6 usec low, or else scanning will no longer work)
// write 0: low 60 usec, high 20 usec
// High time is based on the recovery time, which is detected during reset
const int32_t low_time = (v & 1) ? 7 : 60;
const int32_t high_time = (v & 1) ? (40 + usec_release) : (2 * usec_release + 20); // Recovery time
uint32_t start = 0;
Dallas_write_bit_ISR(v, gpio_pin_rx, gpio_pin_tx, low_time, high_time, start);
// Minimum Recovery time
delayMicroseconds(10);
while (usecPassedSince_fast(start) < high_time) {
// output remains high
}
}
/*********************************************************************************************\
* Dallas Write byte
\*********************************************************************************************/
static void Dallas_write(uint8_t ByteToWrite, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
uint8_t bitMask;
Dallas_pinHigh;
# ifdef DEBUG_LOGIC_ANALYZER_PIN
// DEBUG code using logic analyzer for timings
DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 1);
# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
Dallas_write_bit((bitMask & ByteToWrite) ? 1 : 0, gpio_pin_rx, gpio_pin_tx);
}
# ifdef DEBUG_LOGIC_ANALYZER_PIN
// DEBUG code using logic analyzer for timings
DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 0);
# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN
}
/*********************************************************************************************\
* Standard function to initiate addressing a sensor.
\*********************************************************************************************/
static bool Dallas_address_ROM(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
if (!Dallas_reset(gpio_pin_rx, gpio_pin_tx)) { return false; }
Dallas_write(0x55, gpio_pin_rx, gpio_pin_tx); // Choose ROM
for (uint8_t i = 0; i < 8; i++) {
Dallas_write(ROM[i], gpio_pin_rx, gpio_pin_tx);
}
return true;
}
// read power supply
# ifndef LIMIT_BUILD_SIZE
static bool Dallas_is_parasite(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx, bool& isParasitePowered)
{
if (!Dallas_address_ROM(ROM, gpio_pin_rx, gpio_pin_tx)) {
return false;
}
Dallas_write(0xB4, gpio_pin_rx, gpio_pin_tx); // read power supply
isParasitePowered = !Dallas_read_bit(gpio_pin_rx, gpio_pin_tx);
return isParasitePowered;
}
# endif // ifndef LIMIT_BUILD_SIZE
void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex, int8_t gpio_pin_rx, int8_t gpio_pin_tx, uint8_t nrVariables) {
if ((gpio_pin_rx == -1) ||
(gpio_pin_tx == -1) ||
@@ -344,6 +531,23 @@ void Dallas_show_sensor_stats_webform_load(const Dallas_SensorData& sensor_data)
# endif // ifndef LIMIT_BUILD_SIZE
static void Dallas_plugin_set_addr(uint8_t addr[], taskIndex_t TaskIndex, uint8_t var_index)
{
if (var_index >= 4) {
return;
}
LoadTaskSettings(TaskIndex);
const uint32_t mask = ~(0xFF << (var_index * 8));
for (uint8_t x = 0; x < 8; x++) {
uint32_t value = (uint32_t)ExtraTaskSettings.TaskDevicePluginConfigLong[x];
value &= mask;
value += (static_cast<uint32_t>(addr[x]) << (var_index * 8));
ExtraTaskSettings.TaskDevicePluginConfigLong[x] = (int32_t)value;
}
Cache.updateExtraTaskSettingsCache();
}
void Dallas_addr_selector_webform_save(taskIndex_t TaskIndex, int8_t gpio_pin_rx, int8_t gpio_pin_tx, uint8_t nrVariables)
{
if ((gpio_pin_rx == -1) ||
@@ -368,17 +572,6 @@ void Dallas_addr_selector_webform_save(taskIndex_t TaskIndex, int8_t gpio_pin_rx
}
}
bool Dallas_plugin(pluginID_t pluginID)
{
constexpr pluginID_t PLUGIN_ID_P004_DALLAS_TEMP(4);
constexpr pluginID_t PLUGIN_ID_P080_DALLAS_IBUTTON(80);
constexpr pluginID_t PLUGIN_ID_P100_DS2423_COUNTER(100);
return (pluginID == PLUGIN_ID_P004_DALLAS_TEMP) ||
(pluginID == PLUGIN_ID_P080_DALLAS_IBUTTON) ||
(pluginID == PLUGIN_ID_P100_DS2423_COUNTER);
}
void Dallas_plugin_get_addr(uint8_t addr[], taskIndex_t TaskIndex, uint8_t var_index)
{
if (var_index >= 4) {
@@ -391,23 +584,6 @@ void Dallas_plugin_get_addr(uint8_t addr[], taskIndex_t TaskIndex, uint8_t var_i
}
}
void Dallas_plugin_set_addr(uint8_t addr[], taskIndex_t TaskIndex, uint8_t var_index)
{
if (var_index >= 4) {
return;
}
LoadTaskSettings(TaskIndex);
const uint32_t mask = ~(0xFF << (var_index * 8));
for (uint8_t x = 0; x < 8; x++) {
uint32_t value = (uint32_t)ExtraTaskSettings.TaskDevicePluginConfigLong[x];
value &= mask;
value += (static_cast<uint32_t>(addr[x]) << (var_index * 8));
ExtraTaskSettings.TaskDevicePluginConfigLong[x] = (int32_t)value;
}
Cache.updateExtraTaskSettingsCache();
}
/*********************************************************************************************\
Dallas Scan bus
\*********************************************************************************************/
@@ -430,21 +606,6 @@ uint8_t Dallas_scan(uint8_t getDeviceROM, uint8_t *ROM, int8_t gpio_pin_rx, int8
return devCount;
}
// read power supply
# ifndef LIMIT_BUILD_SIZE
bool Dallas_is_parasite(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx, bool& isParasitePowered)
{
if (!Dallas_address_ROM(ROM, gpio_pin_rx, gpio_pin_tx)) {
return false;
}
Dallas_write(0xB4, gpio_pin_rx, gpio_pin_tx); // read power supply
isParasitePowered = !Dallas_read_bit(gpio_pin_rx, gpio_pin_tx);
return isParasitePowered;
}
# endif // ifndef LIMIT_BUILD_SIZE
/*
void Dallas_startConversion(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
@@ -458,10 +619,91 @@ bool Dallas_is_parasite(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pi
}
*/
/*********************************************************************************************\
* Dallas Read byte
\*********************************************************************************************/
static uint8_t Dallas_read(int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if (Dallas_read_bit(gpio_pin_rx, gpio_pin_tx)) {
r |= bitMask;
}
}
return r;
}
/*********************************************************************************************\
* Dallas Calculate CRC8 and compare it of addr[0-7] and compares it to addr[8]
\*********************************************************************************************/
static bool Dallas_crc8(const uint8_t *addr)
{
uint8_t crc = 0;
uint8_t len = 8;
while (len--)
{
uint8_t inbyte = *addr++; // from 0 to 7
for (uint8_t i = 8; i; i--)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) { crc ^= 0x8C; }
inbyte >>= 1;
}
}
return crc == *addr; // addr 8
}
/*********************************************************************************************\
* Dallas Calculate CRC16
\*********************************************************************************************/
# ifdef USES_P100
static uint16_t Dallas_crc16(const uint8_t *input, uint16_t len, uint16_t crc)
{
static const uint8_t oddparity[16] =
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
for (uint16_t i = 0; i < len; i++) {
// Even though we're just copying a byte from the input,
// we'll be doing 16-bit computation with it.
uint16_t cdata = input[i];
cdata = (cdata ^ crc) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) {
crc ^= 0xC001;
}
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
return crc;
}
# endif // ifdef USES_P100
/*********************************************************************************************\
* Dallas Read temperature from scratchpad
\*********************************************************************************************/
Dallas_read_result Dallas_readTemp(const uint8_t ROM[8], float *value, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
enum class Dallas_read_result {
OK,
NoReply,
CRCerr,
PowerOnResetValue
};
static Dallas_read_result Dallas_readTemp(const uint8_t ROM[8], float *value, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
int16_t DSTemp;
uint8_t ScratchPad[12]{};
@@ -673,7 +915,7 @@ bool Dallas_readCounter(const uint8_t ROM[8], float *value, int8_t gpio_pin_rx,
/*********************************************************************************************\
* Dallas Check for MAX31826 fixed 12 bit resolution, see datasheet page 9 'Memory'
\*********************************************************************************************/
bool Dallas_check_hasFixedResolution(const uint8_t ROM[8], const uint8_t ScratchPad[12]) {
static bool Dallas_check_hasFixedResolution(const uint8_t ROM[8], const uint8_t ScratchPad[12]) {
return (0x3B == ROM[0]) && // MAX31826: Family code 0x3B
(0xFF == ScratchPad[2]) && // All 1s
(0xFF == ScratchPad[3]) &&
@@ -1068,232 +1310,6 @@ uint8_t Dallas_search(uint8_t *newAddr, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
return search_result;
}
/*********************************************************************************************\
* Dallas Read byte
\*********************************************************************************************/
uint8_t Dallas_read(int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
uint8_t bitMask;
uint8_t r = 0;
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
if (Dallas_read_bit(gpio_pin_rx, gpio_pin_tx)) {
r |= bitMask;
}
}
return r;
}
/*********************************************************************************************\
* Dallas Write byte
\*********************************************************************************************/
void Dallas_write(uint8_t ByteToWrite, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
uint8_t bitMask;
Dallas_pinHigh;
# ifdef DEBUG_LOGIC_ANALYZER_PIN
// DEBUG code using logic analyzer for timings
DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 1);
# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN
for (bitMask = 0x01; bitMask; bitMask <<= 1) {
Dallas_write_bit((bitMask & ByteToWrite) ? 1 : 0, gpio_pin_rx, gpio_pin_tx);
}
# ifdef DEBUG_LOGIC_ANALYZER_PIN
// DEBUG code using logic analyzer for timings
DIRECT_pinWrite(DEBUG_LOGIC_ANALYZER_PIN, 0);
# endif // ifdef DEBUG_LOGIC_ANALYZER_PIN
}
/*********************************************************************************************\
* Dallas Read bit
\*********************************************************************************************/
uint8_t Dallas_read_bit(int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
if (gpio_pin_rx == -1) { return 0; }
if (gpio_pin_tx == -1) { return 0; }
uint32_t start;
const uint8_t r = Dallas_read_bit_ISR(gpio_pin_rx, gpio_pin_tx, start);
// Recovery time, make sure we at least wait for 10 usec + RC-rise time
delayMicroseconds(2 * usec_release + 10);
while (usecPassedSince_fast(start) < 60) {
// Allow for some
// Wait for another 45 usec
// Complete read cycle:
// LOW: 6 usec
// Float: 9 msec
// Read value. Typically the sensor keeps the level low for 27 usec.
// Wait for 55 usec => complete cycle = 6 + 9 + 55 = 70 usec.
}
return r;
}
uint8_t DALLAS_IRAM_ATTR Dallas_read_bit_ISR(
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
uint32_t& start)
{
uint8_t r = 0;
ISR_noInterrupts();
Dallas_pinLow;
start = micros();
// delayMicroseconds(1);
// Make sure there is at least 5 usec 'low' level.
// Minimum state by Infineon, however other brands, like Analog,
// claim lower minimum.
while (usecPassedSince_fast(start) < 4) {}
// Set to 'input', state will be pulled high by pull-up resistor
// This will take t_RC, which is typically 2 - 3 usec.
// We have to wait upto 15 usec to see the pin be pulled up,
// otherwise it is apparently be pulled low by the sensor
Dallas_pinInput;
if (Dallas_waitForPinHigh(gpio_pin_rx, start, 15 + usec_release)) {
// Wait for max 15 usec to have a high level
r = 1;
Dallas_pinHigh;
}
ISR_interrupts();
if (r == 0) {
// Wait upto 60 usec to have a high level
// Pin should be released within 15 ... 60 usec from start of read slot.
// We must make sure we don't try to do a strong pull-up
// while the sensor is still trying to pull-down.
Dallas_waitForPinHigh(gpio_pin_rx, start, 60);
}
// Pull high again so we can support parasite mode for 1 sensor
// Sending out a high signal level is stronger than a pull-up resistor can supply
Dallas_pinHigh;
return r;
}
/*********************************************************************************************\
* Dallas Write bit
\*********************************************************************************************/
void Dallas_write_bit(uint8_t v, int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
if (gpio_pin_tx == -1) { return; }
// Determine times in usec for high and low
// write 1: low 6 usec, high 64 usec (no less than 6 usec low, or else scanning will no longer work)
// write 0: low 60 usec, high 20 usec
// High time is based on the recovery time, which is detected during reset
const int32_t low_time = (v & 1) ? 7 : 60;
const int32_t high_time = (v & 1) ? (40 + usec_release) : (2 * usec_release + 20); // Recovery time
uint32_t start = 0;
Dallas_write_bit_ISR(v, gpio_pin_rx, gpio_pin_tx, low_time, high_time, start);
// Minimum Recovery time
delayMicroseconds(10);
while (usecPassedSince_fast(start) < high_time) {
// output remains high
}
}
void DALLAS_IRAM_ATTR Dallas_write_bit_ISR(uint8_t v,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
int32_t low_time,
int32_t high_time,
uint32_t& start)
{
ISR_noInterrupts();
start = micros();
Dallas_pinLow;
while (usecPassedSince_fast(start) < low_time) {
// output remains low
}
start = micros();
Dallas_pinHigh;
ISR_interrupts();
}
/*********************************************************************************************\
* Standard function to initiate addressing a sensor.
\*********************************************************************************************/
bool Dallas_address_ROM(const uint8_t ROM[8], int8_t gpio_pin_rx, int8_t gpio_pin_tx)
{
if (!Dallas_reset(gpio_pin_rx, gpio_pin_tx)) { return false; }
Dallas_write(0x55, gpio_pin_rx, gpio_pin_tx); // Choose ROM
for (uint8_t i = 0; i < 8; i++) {
Dallas_write(ROM[i], gpio_pin_rx, gpio_pin_tx);
}
return true;
}
/*********************************************************************************************\
* Dallas Calculate CRC8 and compare it of addr[0-7] and compares it to addr[8]
\*********************************************************************************************/
bool Dallas_crc8(const uint8_t *addr)
{
uint8_t crc = 0;
uint8_t len = 8;
while (len--)
{
uint8_t inbyte = *addr++; // from 0 to 7
for (uint8_t i = 8; i; i--)
{
uint8_t mix = (crc ^ inbyte) & 0x01;
crc >>= 1;
if (mix) { crc ^= 0x8C; }
inbyte >>= 1;
}
}
return crc == *addr; // addr 8
}
/*********************************************************************************************\
* Dallas Calculate CRC16
\*********************************************************************************************/
uint16_t Dallas_crc16(const uint8_t *input, uint16_t len, uint16_t crc)
{
static const uint8_t oddparity[16] =
{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
for (uint16_t i = 0; i < len; i++) {
// Even though we're just copying a byte from the input,
// we'll be doing 16-bit computation with it.
uint16_t cdata = input[i];
cdata = (cdata ^ crc) & 0xff;
crc >>= 8;
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) {
crc ^= 0xC001;
}
cdata <<= 6;
crc ^= cdata;
cdata <<= 1;
crc ^= cdata;
}
return crc;
}
void Dallas_SensorData::clear() {
addr = 0u;
value = 0.0f;
+21 -78
View File
@@ -50,9 +50,10 @@ struct Dallas_SensorData {
bool valueRead{};
bool lastReadError{};
bool fixed_resolution{};
#ifndef LIMIT_BUILD_SIZE
# ifndef LIMIT_BUILD_SIZE
bool parasitePowered{};
#endif
# endif
};
@@ -63,7 +64,7 @@ struct Dallas_SensorData {
extern unsigned char ROM_NO[8];
extern uint8_t LastDiscrepancy;
extern uint8_t LastFamilyDiscrepancy;
extern bool LastDeviceFlag;
extern bool LastDeviceFlag;
/*********************************************************************************************\
@@ -77,42 +78,30 @@ extern int32_t presence_end; // End presence condition (minimal 60 usec, typ:
/*********************************************************************************************\
Format 1-wire address
\*********************************************************************************************/
const __FlashStringHelper* Dallas_getModel(uint8_t family,
const bool hasFixedResolution = false);
String Dallas_format_address(const uint8_t addr[],
const bool hasFixedResolution = false);
String Dallas_format_address(const uint8_t addr[],
const bool hasFixedResolution = false);
uint64_t Dallas_addr_to_uint64(const uint8_t addr[]);
uint64_t Dallas_addr_to_uint64(const uint8_t addr[]);
void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
uint8_t nrVariables = 1);
void Dallas_uint64_to_addr(uint64_t value,
uint8_t addr[]);
void Dallas_addr_selector_webform_load(taskIndex_t TaskIndex,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
uint8_t nrVariables = 1);
#ifndef LIMIT_BUILD_SIZE
# ifndef LIMIT_BUILD_SIZE
void Dallas_show_sensor_stats_webform_load(const Dallas_SensorData& sensor_data);
#endif
# endif
void Dallas_addr_selector_webform_save(taskIndex_t TaskIndex,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
uint8_t nrVariables = 1);
bool Dallas_plugin(pluginID_t pluginID);
// Load ROM address from tasksettings
void Dallas_plugin_get_addr(uint8_t addr[],
taskIndex_t TaskIndex,
uint8_t var_index = 0);
void Dallas_plugin_set_addr(uint8_t addr[],
taskIndex_t TaskIndex,
uint8_t var_index = 0);
/*********************************************************************************************\
Dallas Scan bus
@@ -125,13 +114,6 @@ uint8_t Dallas_scan(uint8_t getDeviceROM,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
// read power supply
#ifndef LIMIT_BUILD_SIZE
bool Dallas_is_parasite(const uint8_t ROM[8],
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
bool & isParasitePowered);
#endif
/*
void Dallas_startConversion(const uint8_t ROM[8],
int8_t gpio_pin_rx,
@@ -141,16 +123,6 @@ bool Dallas_is_parasite(const uint8_t ROM[8],
/*********************************************************************************************\
* Dallas data from scratchpad
\*********************************************************************************************/
enum class Dallas_read_result {
OK,
NoReply,
CRCerr,
PowerOnResetValue
};
Dallas_read_result Dallas_readTemp(const uint8_t ROM[8],
float *value,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
# ifdef USES_P080
bool Dallas_readiButton(const uint8_t addr[8],
@@ -205,63 +177,34 @@ uint8_t Dallas_search(uint8_t *newAddr,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
/*********************************************************************************************\
* Dallas Read byte
\*********************************************************************************************/
uint8_t Dallas_read(int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
/*********************************************************************************************\
* Dallas Write byte
\*********************************************************************************************/
void Dallas_write(uint8_t ByteToWrite,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
/*********************************************************************************************\
* Dallas Read bit
* See https://github.com/espressif/arduino-esp32/issues/1335
\*********************************************************************************************/
uint8_t Dallas_read_bit(int8_t gpio_pin_rx,
/*
uint8_t Dallas_read_bit(int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
uint8_t Dallas_read_bit_ISR(int8_t gpio_pin_rx,
uint8_t Dallas_read_bit_ISR(int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
uint32_t& start);
*/
/*********************************************************************************************\
* Dallas Write bit
* See https://github.com/espressif/arduino-esp32/issues/1335
\*********************************************************************************************/
void Dallas_write_bit(uint8_t v,
/*
void Dallas_write_bit(uint8_t v,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
void Dallas_write_bit_ISR(uint8_t v,
void Dallas_write_bit_ISR(uint8_t v,
int8_t gpio_pin_rx,
int8_t gpio_pin_tx,
int32_t low_time,
int32_t high_time,
uint32_t& start);
/*********************************************************************************************\
* Standard function to initiate addressing a sensor.
\*********************************************************************************************/
bool Dallas_address_ROM(const uint8_t ROM[8],
int8_t gpio_pin_rx,
int8_t gpio_pin_tx);
/*********************************************************************************************\
* Dallas Calculate CRC8 and compare it of addr[0-7] and compares it to addr[8]
\*********************************************************************************************/
bool Dallas_crc8(const uint8_t *addr);
/*********************************************************************************************\
* Dallas Calculate CRC16
\*********************************************************************************************/
uint16_t Dallas_crc16(const uint8_t *input,
uint16_t len,
uint16_t crc);
*/
#endif // if FEATURE_DALLAS_HELPER
+1 -1
View File
@@ -9,7 +9,7 @@
#include "../Helpers/_Plugin_init.h"
void stream_json_timing_stats(const TimingStats& stats, long timeSinceLastReset) {
static void stream_json_timing_stats(const TimingStats& stats, long timeSinceLastReset) {
uint32_t minVal, maxVal;
uint32_t count = stats.getMinMax(minVal, maxVal);
float call_per_sec = static_cast<float>(count) / static_cast<float>(timeSinceLastReset) * 1000.0f;
-2
View File
@@ -9,8 +9,6 @@
#ifdef WEBSERVER_NEW_UI
#include "../DataStructs/TimingStats.h"
void stream_json_timing_stats(const TimingStats& stats, long timeSinceLastReset);
void jsonStatistics(bool clearStats);
#endif
#endif // if FEATURE_TIMING_STATS
+180
View File
@@ -0,0 +1,180 @@
#include "../Helpers/ESPEasy_CrashHandler.h"
#include "../Globals/Settings.h"
#include "../Globals/RTC.h"
#define CRASHHANDLER_MIN_BOOTLOOP_COUNT 10
/********************************************************************************************\
Disable Plugin, based on bootFailedCount
\*********************************************************************************************/
static uint8_t disablePlugin(uint8_t bootFailedCount) {
for (taskIndex_t i = 0; i < TASKS_MAX && bootFailedCount > 0; ++i) {
if (Settings.TaskDeviceEnabled[i]) {
--bootFailedCount;
if (bootFailedCount == 0) {
// Disable temporarily as unit crashed
// FIXME TD-er: Should this be stored?
Settings.TaskDeviceEnabled[i] = false;
}
}
}
return bootFailedCount;
}
static uint8_t disableAllPlugins(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
for (taskIndex_t i = 0; i < TASKS_MAX; ++i) {
// Disable temporarily as unit crashed
// FIXME TD-er: Should this be stored?
Settings.TaskDeviceEnabled[i] = false;
}
}
return bootFailedCount;
}
/********************************************************************************************\
Disable Controller, based on bootFailedCount
\*********************************************************************************************/
static uint8_t disableController(uint8_t bootFailedCount) {
for (controllerIndex_t i = 0; i < CONTROLLER_MAX && bootFailedCount > 0; ++i) {
if (Settings.ControllerEnabled[i]) {
--bootFailedCount;
if (bootFailedCount == 0) {
Settings.ControllerEnabled[i] = false;
}
}
}
return bootFailedCount;
}
static uint8_t disableAllControllers(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) {
Settings.ControllerEnabled[i] = false;
}
}
return bootFailedCount;
}
/********************************************************************************************\
Disable Notification, based on bootFailedCount
\*********************************************************************************************/
#if FEATURE_NOTIFIER
static uint8_t disableNotification(uint8_t bootFailedCount) {
for (uint8_t i = 0; i < NOTIFICATION_MAX && bootFailedCount > 0; ++i) {
if (Settings.NotificationEnabled[i]) {
--bootFailedCount;
if (bootFailedCount == 0) {
Settings.NotificationEnabled[i] = false;
}
}
}
return bootFailedCount;
}
static uint8_t disableAllNotifications(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
for (uint8_t i = 0; i < NOTIFICATION_MAX; ++i) {
Settings.NotificationEnabled[i] = false;
}
}
return bootFailedCount;
}
#endif // if FEATURE_NOTIFIER
/********************************************************************************************\
Disable Network Interfaces, based on bootFailedCount
\*********************************************************************************************/
static uint8_t disableNetwork(uint8_t bootFailedCount)
{
for (ESPEasy::net::networkIndex_t i = 0; i < NETWORK_MAX && bootFailedCount > 0; ++i) {
if (Settings.getNetworkEnabled(i)) {
--bootFailedCount;
if (bootFailedCount == 0) {
Settings.setNetworkEnabled(i, false);
}
}
}
return bootFailedCount;
}
static uint8_t disableAllNetworks(uint8_t bootFailedCount)
{
if (bootFailedCount > 0) {
--bootFailedCount;
for (ESPEasy::net::networkIndex_t i = 0; i < NETWORK_MAX; ++i) {
Settings.setNetworkEnabled(i, false);
}
}
return bootFailedCount;
}
/********************************************************************************************\
Disable Rules, based on bootFailedCount
\*********************************************************************************************/
static uint8_t disableRules(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
Settings.UseRules = false;
}
return bootFailedCount;
}
void disableFailingComponent()
{
if ((RTC.bootFailedCount > CRASHHANDLER_MIN_BOOTLOOP_COUNT) && (RTC.bootCounter > CRASHHANDLER_MIN_BOOTLOOP_COUNT)) {
uint8_t toDisable = RTC.bootFailedCount - CRASHHANDLER_MIN_BOOTLOOP_COUNT;
toDisable = disablePlugin(toDisable);
if (toDisable != 0) {
toDisable = disableController(toDisable);
}
#if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableNotification(toDisable);
}
#endif // if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableNetwork(toDisable);
}
if (toDisable != 0) {
toDisable = disableRules(toDisable);
}
if (toDisable != 0) {
toDisable = disableAllPlugins(toDisable);
}
if (toDisable != 0) {
toDisable = disableAllControllers(toDisable);
}
#if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableAllNotifications(toDisable);
}
#endif // if FEATURE_NOTIFIER
if (toDisable != 0) {
toDisable = disableAllNetworks(toDisable);
}
}
}
+13
View File
@@ -0,0 +1,13 @@
#pragma once
/********************************************************************************************\
ESPEasy will start disabling components when a bootloop is detected.
These will only be disabled in memory, the disabled state will not be saved.
So whenever an ESPEasy node suddenly doesn't have some task or controller disabled,
the disabled component is likely causing the node to crash.
This can be some programming error, a configuration error
or maybe a bad device returning invalid data.
\*********************************************************************************************/
void disableFailingComponent();
+81 -201
View File
@@ -80,7 +80,7 @@ String patch_fname(const String& fname) {
file system error handling
Look here for error # reference: https://github.com/pellepl/spiffs/blob/master/src/spiffs.h
\*********************************************************************************************/
String FileError(int line, const char *fname)
static String FileError(int line, const char *fname)
{
String log = strformat(F("FS : Error while reading/writing %s in %d"), fname, line);
@@ -88,6 +88,10 @@ String FileError(int line, const char *fname)
return log;
}
// Macro used to make file system operations a bit more readable.
#define SPIFFS_CHECK(result, fname) if (!(result)) { return(FileError(__LINE__, fname)); }
/********************************************************************************************\
Keep track of number of flash writes.
\*********************************************************************************************/
@@ -100,7 +104,7 @@ void flashCount()
saveToRTC();
}
String flashGuard()
static String flashGuard()
{
#ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("flashGuard"));
@@ -121,11 +125,7 @@ String flashGuard()
if (flashErr.length()) return flashErr; }
String appendLineToFile(const String& fname, const String& line) {
return appendToFile(fname, reinterpret_cast<const uint8_t *>(line.c_str()), line.length());
}
String appendToFile(const String& fname, const uint8_t *data, unsigned int size) {
static String appendToFile(const String& fname, const uint8_t *data, unsigned int size) {
fs::File f = tryOpenFile(fname, "a+");
SPIFFS_CHECK(f, fname.c_str());
@@ -134,6 +134,10 @@ String appendToFile(const String& fname, const uint8_t *data, unsigned int size)
return EMPTY_STRING;
}
String appendLineToFile(const String& fname, const String& line) {
return appendToFile(fname, reinterpret_cast<const uint8_t *>(line.c_str()), line.length());
}
bool fileExists(const __FlashStringHelper *fname)
{
return fileExists(String(fname));
@@ -234,13 +238,14 @@ fs::File tryOpenFile(const String& fname, const String& mode, FileDestination_e
return f;
}
bool fileMatchesTaskSettingsType(const String& fname) {
static bool fileMatchesTaskSettingsType(const String& fname) {
const String config_dat_file = patch_fname(getFileName(FileType::CONFIG_DAT));
return config_dat_file.equalsIgnoreCase(patch_fname(fname));
}
bool tryRenameFile(const String& fname_old, const String& fname_new, FileDestination_e destination) {
#if FEATURE_DOWNLOAD
static bool tryRenameFile(const String& fname_old, const String& fname_new, FileDestination_e destination) {
clearFileCaches();
if (fileExists(fname_old) && !fileExists(fname_new)) {
@@ -264,6 +269,7 @@ bool tryRenameFile(const String& fname_old, const String& fname_new, FileDestina
}
return false;
}
#endif
bool tryDeleteFile(const String& fname, FileDestination_e destination) {
if (fname.length() > 0)
@@ -321,7 +327,7 @@ bool tryDeleteFile(const String& fname, FileDestination_e destination) {
/********************************************************************************************\
Fix stuff to clear out differences between releases
\*********************************************************************************************/
bool BuildFixes()
static bool BuildFixes()
{
if (Settings.Build == get_build_nr()) {
// Not changed
@@ -664,7 +670,7 @@ uint32_t getWiFi_CalibrationVersion()
return 0;
}
bool setWiFi_CalibrationVersion() {
static bool setWiFi_CalibrationVersion() {
// Store used IDF version in NVS
const uint32_t idfVersion = ESP_IDF_VERSION;
ESPEasy_NVS_Helper preferences;
@@ -675,7 +681,7 @@ bool setWiFi_CalibrationVersion() {
return false;
}
String formatIdfVersion(uint32_t idfVer) {
static String formatIdfVersion(uint32_t idfVer) {
return strformat(
F("%u.%u.%u"),
(idfVer >> 16) & 0xFF,
@@ -761,7 +767,7 @@ int getPartionCount(uint8_t pType, uint8_t pSubType) {
#endif // ifdef ESP32
#ifdef ESP8266
bool clearPartition(ESP8266_partition_type ptype) {
static bool clearPartition(ESP8266_partition_type ptype) {
uint32_t address;
int32_t size;
int32_t sector = getPartitionInfo(ESP8266_partition_type::rf_cal, address, size);
@@ -871,63 +877,7 @@ String SaveSettings(bool forFactoryReset)
return err;
}
String SaveSecuritySettings(bool forFactoryReset) {
String err;
SecuritySettings.validate();
memcpy(SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16);
if (forFactoryReset) {
SecuritySettings.forceSave();
}
if (SecuritySettings.updateChecksum()) {
// Settings have changed, save to file.
err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(),
0,
reinterpret_cast<const uint8_t *>(&SecuritySettings),
sizeof(SecuritySettings));
// Security settings are saved, may be update of WiFi settings or hostname.
if (!forFactoryReset) {
if (SecuritySettings.hasWiFiCredentials() && (active_network_medium == ESPEasy::net::NetworkMedium_t::WIFI)) {
ESPEasy::net::wifi::WiFi_AP_Candidates.force_reload(); // Force reload of the credentials and found APs from the last scan
if (!ESPEasy::net::NetworkConnected()) {
// WiFiEventData.wifiConnectAttemptNeeded = true;
ESPEasy::net::wifi::initWiFi();// resetWiFi();
String dummy;
ESPEasy::net::NWPluginCall(
NWPlugin::Function::NWPLUGIN_CREDENTIALS_CHANGED, 0, dummy);
}
}
}
}
#ifndef BUILD_NO_DEBUG
else {
addLog(LOG_LEVEL_INFO, F("Skip saving SecuritySettings, not changed"));
}
#endif // ifndef BUILD_NO_DEBUG
// FIXME TD-er: How to check if these have changed?
if (forFactoryReset) {
ExtendedControllerCredentials.clear();
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
SecuritySettings_deviceSpecific.clear();
#endif
}
ExtendedControllerCredentials.save();
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
SecuritySettings_deviceSpecific.save();
#endif
if (!forFactoryReset) {
afterloadSettings();
}
return err;
}
void afterloadSettings() {
static void afterloadSettings() {
ExtraTaskSettings.clear(); // make sure these will not contain old settings.
if ((Settings.Version != VERSION) || (Settings.PID != ESP_PROJECT_PID)) {
@@ -997,6 +947,64 @@ void afterloadSettings() {
ESPEasy::net::CheckRunningServices(true); // To update changes in hostname.
}
String SaveSecuritySettings(bool forFactoryReset) {
String err;
SecuritySettings.validate();
memcpy(SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16);
if (forFactoryReset) {
SecuritySettings.forceSave();
}
if (SecuritySettings.updateChecksum()) {
// Settings have changed, save to file.
err = SaveToFile(SettingsType::getSettingsFileName(SettingsType::Enum::SecuritySettings_Type).c_str(),
0,
reinterpret_cast<const uint8_t *>(&SecuritySettings),
sizeof(SecuritySettings));
// Security settings are saved, may be update of WiFi settings or hostname.
if (!forFactoryReset) {
if (SecuritySettings.hasWiFiCredentials() && (active_network_medium == ESPEasy::net::NetworkMedium_t::WIFI)) {
ESPEasy::net::wifi::WiFi_AP_Candidates.force_reload(); // Force reload of the credentials and found APs from the last scan
if (!ESPEasy::net::NetworkConnected()) {
// WiFiEventData.wifiConnectAttemptNeeded = true;
ESPEasy::net::wifi::initWiFi();// resetWiFi();
String dummy;
ESPEasy::net::NWPluginCall(
NWPlugin::Function::NWPLUGIN_CREDENTIALS_CHANGED, 0, dummy);
}
}
}
}
#ifndef BUILD_NO_DEBUG
else {
addLog(LOG_LEVEL_INFO, F("Skip saving SecuritySettings, not changed"));
}
#endif // ifndef BUILD_NO_DEBUG
// FIXME TD-er: How to check if these have changed?
if (forFactoryReset) {
ExtendedControllerCredentials.clear();
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
SecuritySettings_deviceSpecific.clear();
#endif
}
ExtendedControllerCredentials.save();
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
SecuritySettings_deviceSpecific.save();
#endif
if (!forFactoryReset) {
afterloadSettings();
}
return err;
}
/********************************************************************************************\
Load settings from file system
\*********************************************************************************************/
@@ -1073,134 +1081,6 @@ String LoadSettings()
return err;
}
/********************************************************************************************\
Disable Plugin, based on bootFailedCount
\*********************************************************************************************/
uint8_t disablePlugin(uint8_t bootFailedCount) {
for (taskIndex_t i = 0; i < TASKS_MAX && bootFailedCount > 0; ++i) {
if (Settings.TaskDeviceEnabled[i]) {
--bootFailedCount;
if (bootFailedCount == 0) {
// Disable temporarily as unit crashed
// FIXME TD-er: Should this be stored?
Settings.TaskDeviceEnabled[i] = false;
}
}
}
return bootFailedCount;
}
uint8_t disableAllPlugins(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
for (taskIndex_t i = 0; i < TASKS_MAX; ++i) {
// Disable temporarily as unit crashed
// FIXME TD-er: Should this be stored?
Settings.TaskDeviceEnabled[i] = false;
}
}
return bootFailedCount;
}
/********************************************************************************************\
Disable Controller, based on bootFailedCount
\*********************************************************************************************/
uint8_t disableController(uint8_t bootFailedCount) {
for (controllerIndex_t i = 0; i < CONTROLLER_MAX && bootFailedCount > 0; ++i) {
if (Settings.ControllerEnabled[i]) {
--bootFailedCount;
if (bootFailedCount == 0) {
Settings.ControllerEnabled[i] = false;
}
}
}
return bootFailedCount;
}
uint8_t disableAllControllers(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
for (controllerIndex_t i = 0; i < CONTROLLER_MAX; ++i) {
Settings.ControllerEnabled[i] = false;
}
}
return bootFailedCount;
}
/********************************************************************************************\
Disable Notification, based on bootFailedCount
\*********************************************************************************************/
#if FEATURE_NOTIFIER
uint8_t disableNotification(uint8_t bootFailedCount) {
for (uint8_t i = 0; i < NOTIFICATION_MAX && bootFailedCount > 0; ++i) {
if (Settings.NotificationEnabled[i]) {
--bootFailedCount;
if (bootFailedCount == 0) {
Settings.NotificationEnabled[i] = false;
}
}
}
return bootFailedCount;
}
uint8_t disableAllNotifications(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
for (uint8_t i = 0; i < NOTIFICATION_MAX; ++i) {
Settings.NotificationEnabled[i] = false;
}
}
return bootFailedCount;
}
#endif // if FEATURE_NOTIFIER
/********************************************************************************************\
Disable Network Interfaces, based on bootFailedCount
\*********************************************************************************************/
uint8_t disableNetwork(uint8_t bootFailedCount)
{
for (ESPEasy::net::networkIndex_t i = 0; i < NETWORK_MAX && bootFailedCount > 0; ++i) {
if (Settings.getNetworkEnabled(i)) {
--bootFailedCount;
if (bootFailedCount == 0) {
Settings.setNetworkEnabled(i, false);
}
}
}
return bootFailedCount;
}
uint8_t disableAllNetworkss(uint8_t bootFailedCount)
{
if (bootFailedCount > 0) {
--bootFailedCount;
for (ESPEasy::net::networkIndex_t i = 0; i < NETWORK_MAX; ++i) {
Settings.setNetworkEnabled(i, false);
}
}
return bootFailedCount;
}
/********************************************************************************************\
Disable Rules, based on bootFailedCount
\*********************************************************************************************/
uint8_t disableRules(uint8_t bootFailedCount) {
if (bootFailedCount > 0) {
--bootFailedCount;
Settings.UseRules = false;
}
return bootFailedCount;
}
bool getAndLogSettingsParameters(bool read, SettingsType::Enum settingsType, int index, int& offset, int& max_size) {
#ifndef BUILD_NO_DEBUG
@@ -2716,14 +2596,14 @@ String downloadFileType(const String& url, const String& user, const String& pas
return error;
}
if (fileExists(filename) && !tryRenameFile(filename, filename_bak)) {
if (fileExists(filename) && !tryRenameFile(filename, filename_bak, FileDestination_e::ANY)) {
return F("Could not rename to _bak");
} else {
// File does not exist (anymore)
if (!tryRenameFile(tmpfile, filename)) {
if (!tryRenameFile(tmpfile, filename, FileDestination_e::ANY)) {
error = F("Could not rename tmp file");
if (tryRenameFile(filename_bak, filename)) {
if (tryRenameFile(filename_bak, filename, FileDestination_e::ANY)) {
error += F("... reverted");
} else {
error += F(" Not reverted!");
-49
View File
@@ -16,23 +16,14 @@
#include "../Globals/CPlugins.h"
/********************************************************************************************\
file system error handling
Look here for error # reference: https://github.com/pellepl/spiffs/blob/master/src/spiffs.h
\*********************************************************************************************/
String FileError(int line, const char *fname);
/********************************************************************************************\
Keep track of number of flash writes.
\*********************************************************************************************/
void flashCount();
String flashGuard();
String appendLineToFile(const String& fname, const String& line);
String appendToFile(const String& fname, const uint8_t *data, unsigned int size);
enum class FileDestination_e : uint8_t {
ANY = 0,
FLASH = 1,
@@ -48,15 +39,8 @@ int fileSize(const String& fname);
fs::File tryOpenFile(const String& fname, const String& mode, FileDestination_e destination = FileDestination_e::ANY);
bool tryRenameFile(const String& fname_old, const String& fname_new, FileDestination_e destination = FileDestination_e::ANY);
bool tryDeleteFile(const String& fname, FileDestination_e destination = FileDestination_e::ANY);
/********************************************************************************************\
Fix stuff to clear out differences between releases
Return true when settings were changed/patched
\*********************************************************************************************/
bool BuildFixes();
/********************************************************************************************\
Mount FS and check config.dat
@@ -121,44 +105,11 @@ String SaveSettings(bool forFactoryReset = false);
String SaveSecuritySettings(bool forFactoryReset = false);
void afterloadSettings();
/********************************************************************************************\
Load settings from file system
\*********************************************************************************************/
String LoadSettings();
/********************************************************************************************\
Disable Plugin, based on bootFailedCount
\*********************************************************************************************/
uint8_t disablePlugin(uint8_t bootFailedCount);
uint8_t disableAllPlugins(uint8_t bootFailedCount);
/********************************************************************************************\
Disable Controller, based on bootFailedCount
\*********************************************************************************************/
uint8_t disableController(uint8_t bootFailedCount);
uint8_t disableAllControllers(uint8_t bootFailedCount);
/********************************************************************************************\
Disable Notification, based on bootFailedCount
\*********************************************************************************************/
#if FEATURE_NOTIFIER
uint8_t disableNotification(uint8_t bootFailedCount);
uint8_t disableAllNotifications(uint8_t bootFailedCount);
#endif
/********************************************************************************************\
Disable Rules, based on bootFailedCount
\*********************************************************************************************/
uint8_t disableRules(uint8_t bootFailedCount);
/********************************************************************************************\
Disable Network Interfaces, based on bootFailedCount
\*********************************************************************************************/
uint8_t disableNetwork(uint8_t bootFailedCount);
uint8_t disableAllNetworkss(uint8_t bootFailedCount);
bool getAndLogSettingsParameters(bool read, SettingsType::Enum settingsType, int index, int& offset, int& max_size);
+2 -2
View File
@@ -34,7 +34,7 @@ tTouchObjects::tTouchObjects() :
* toString: Display-value for the touch action
***************************************************************************/
# if TOUCH_FEATURE_EXTENDED_TOUCH
const __FlashStringHelper* toString(Touch_action_e action) {
static const __FlashStringHelper* toString(Touch_action_e action) {
switch (action) {
case Touch_action_e::Default: return F("Default");
case Touch_action_e::ActivateGroup: return F("Activate Group");
@@ -52,7 +52,7 @@ const __FlashStringHelper* toString(Touch_action_e action) {
* toString: Display-value for the swipe action
***************************************************************************/
# if TOUCH_FEATURE_EXTENDED_TOUCH && TOUCH_FEATURE_SWIPE
const __FlashStringHelper* toString(Swipe_action_e action) {
static const __FlashStringHelper* toString(Swipe_action_e action) {
switch (action) {
case Swipe_action_e::Up: return F("Up");
case Swipe_action_e::UpRight: return F("Up-Right");
-5
View File
@@ -280,11 +280,6 @@ enum class Swipe_action_e : uint8_t {
};
# endif // if TOUCH_FEATURE_EXTENDED_TOUCH && TOUCH_FEATURE_SWIPE
const __FlashStringHelper* toString(Touch_action_e action);
# if TOUCH_FEATURE_EXTENDED_TOUCH && TOUCH_FEATURE_SWIPE
const __FlashStringHelper* toString(Swipe_action_e action);
# endif // if TOUCH_FEATURE_EXTENDED_TOUCH && TOUCH_FEATURE_SWIPE
class ESPEasy_TouchHandler {
public:
@@ -82,7 +82,7 @@ bool ESPEasy_key_value_store_import_export::do_export(
}
bool getNextKeyValue(String& json, String& key, String& value)
static bool getNextKeyValue(String& json, String& key, String& value)
{
String keyValueStr;
int pos = json.indexOf(',');
+2 -2
View File
@@ -65,12 +65,12 @@ uint64_t computeDecimalFactorForDecimals(int nrDecimals)
}
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
double estimateDoubleEpsilon(const double& a, const double& b)
static double estimateDoubleEpsilon(const double& a, const double& b)
{
return std::max(std::abs(a), std::abs(b)) * ESPEASY_DOUBLE_EPSILON;
}
#endif
float estimateEpsilon(const float& a, const float& b)
static float estimateEpsilon(const float& a, const float& b)
{
return std::max(std::abs(a), std::abs(b)) * ESPEASY_FLOAT_EPSILON;
}
+9 -6
View File
@@ -22,13 +22,14 @@ uint32_t unix_time_frac_to_micros(uint32_t unix_time_frac)
{
return static_cast<float>(unix_time_frac) / 4294.967f;
}
uint32_t millis_to_unix_time_frac(uint32_t millis)
/*
static uint32_t millis_to_unix_time_frac(uint32_t millis)
{
return static_cast<float>(millis) * 4294967.0f;
}
*/
uint32_t micros_to_unix_time_frac(uint32_t micros)
static uint32_t micros_to_unix_time_frac(uint32_t micros)
{
return static_cast<float>(micros) * 4294.967f;
}
@@ -58,7 +59,8 @@ uint32_t micros_to_sec_usec(int64_t micros, uint32_t& usec)
return static_cast<uint32_t>(seconds);
}
uint64_t sec_time_frac_to_uptime_offset_usec(const uint32_t& seconds,
/*
static uint64_t sec_time_frac_to_uptime_offset_usec(const uint32_t& seconds,
uint32_t time_frac)
{
const uint64_t unix_time_usec = sec_time_frac_to_Micros(seconds, time_frac);
@@ -67,13 +69,14 @@ uint64_t sec_time_frac_to_uptime_offset_usec(const uint32_t& seconds,
return unix_time_usec;
return unix_time_usec - cur_usec;
}
*/
bool isLeapYear(int year) {
static bool isLeapYear(int year) {
return (year > 0) && !(year % 4) && ((year % 100) || !(year % 400));
}
uint8_t getMonthDays(int year, uint8_t month) {
static uint8_t getMonthDays(int year, uint8_t month) {
const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if ((month == 1) && isLeapYear(year)) {
-7
View File
@@ -79,25 +79,18 @@ inline bool usecTimeOutReached(const uint64_t& timer) {
uint32_t unix_time_frac_to_millis(uint32_t unix_time_frac);
uint32_t unix_time_frac_to_micros(uint32_t unix_time_frac);
uint32_t millis_to_unix_time_frac(uint32_t millis);
uint32_t micros_to_unix_time_frac(uint32_t micros);
uint32_t micros_to_sec_time_frac(int64_t micros, uint32_t& unix_time_frac);
uint64_t sec_time_frac_to_Micros(uint32_t seconds, uint32_t time_frac);
uint32_t micros_to_sec_usec(int64_t micros, uint32_t& usec);
uint64_t sec_time_frac_to_uptime_offset_usec(const uint32_t& seconds,
uint32_t time_frac = 0);
/********************************************************************************************\
Unix Time computations
\*********************************************************************************************/
bool isLeapYear(int year);
// Get number of days in a month.
// Month starts at 0 for January.
uint8_t getMonthDays(int year, uint8_t month);
uint8_t getMonthDays(const struct tm& tm);
uint32_t makeTime(const struct tm& tm);
-2
View File
@@ -4,8 +4,6 @@
#include "../../ESPEasy_common.h"
// Macro used to make file system operations a bit more readable.
#define SPIFFS_CHECK(result, fname) if (!(result)) { return(FileError(__LINE__, fname)); }
#ifdef USE_LITTLEFS
#ifdef ESP32
+186 -181
View File
@@ -15,6 +15,192 @@
# include <ArduinoJson.h>
/**
* @brief Reads and processes keys from a json.keys file and navigates the JSON document.
*/
static void readAndProcessJsonKeys(DynamicJsonDocument *root, int numJson) {
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
int nr_decimals = ESPEASY_DOUBLE_NR_DECIMALS;
# else // ifdef FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
int nr_decimals = ESPEASY_FLOAT_NR_DECIMALS;
# endif // ifdef FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
// Open the `json.keys` file
# ifdef ESP8266
const String fileName = F("json.keys");
# else // ifdef ESP8266
const String fileName = F("/json.keys");
# endif // ifdef ESP8266
if (!fileExists(fileName)) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
addLogMove(LOG_LEVEL_ERROR, strformat(F("%s does not exist!"), fileName.c_str()));
}
return;
}
File keyFile = ESPEASY_FS.open(fileName, "r");
int keyCount = 0;
int successfullyProcessedCount = 0; // Counter for successfully processed keys
String csvOutput; // Collect values as a CSV string
while (keyFile.available()) {
String key = keyFile.readStringUntil('\n');
key.trim(); // Remove extra spaces or newlines
if (key.isEmpty()) {
continue;
}
int keyNumber = 0;
// Extract the number prefix (before the first dot)
if (key.indexOf(':') != -1) {
keyNumber = key.substring(0, key.indexOf(':')).toInt();
key = key.substring(key.indexOf(':') + 1);
}
// Only process keys that match the filterNumber (or process all if no match)
if ((numJson > 0) && (keyNumber != numJson)) {
continue; // Skip this key if it doesn't match the filter number
}
keyCount++;
if (keyCount > MAX_KEYS) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
addLogMove(LOG_LEVEL_ERROR, strformat(F("Warning: More than %d keys in %s"), MAX_KEYS, fileName.c_str()));
}
}
# if FEATURE_JSON_PARSE
const String val = getJsonValue(root, key, false); // Return arrays and objects as csv, _not_ JSON formatted
if (!val.isEmpty()) {
successfullyProcessedCount++;
csvOutput += val;
csvOutput += ',';
}
# else // if FEATURE_JSON_PARSE
// Process the key and navigate the JSON
JsonVariant value = *root;
size_t start = 0, end;
while ((end = key.indexOf('.', start)) != (unsigned int)-1) {
String part = key.substring(start, end);
start = end + 1;
// Look for an array e.g., "result[0]" → object "result", index 0
int bracketStart = part.indexOf('[');
if (bracketStart != -1) {
String objectName = part.substring(0, bracketStart);
String indexStr = part.substring(bracketStart + 1, part.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName]; // Access the object
}
if (value.is<JsonArray>()) {
int index = indexStr.toInt();
value = value[index];
} else {
value = value[indexStr]; // fallback if not actually array
}
} else {
// Normal object access without array
value = value[part];
}
if (value.isNull()) {
break; // Key path is invalid
}
}
if (!value.isNull()) {
successfullyProcessedCount++;
String lastPart = key.substring(start);
int bracketStart = lastPart.indexOf('[');
if (bracketStart != -1) {
String objectName = lastPart.substring(0, bracketStart);
String indexStr = lastPart.substring(bracketStart + 1, lastPart.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName];
}
if (value.is<JsonArray>()) {
value = value[indexStr.toInt()];
} else {
value = value[indexStr];
}
} else {
value = value[lastPart];
}
}
// Append the value to the CSV string if it exists
if (!value.isNull()) {
if (value.is<int>()) {
csvOutput += String(value.as<int>());
} else if (value.is<float>()) {
csvOutput += doubleToString(value.as<double>(), nr_decimals, true);
} else if (value.is<const char *>()) {
csvOutput += String(value.as<const char *>());
} else if (value.is<JsonArray>()) {
// If the value is an array, iterate over its elements
JsonArray array = value.as<JsonArray>();
size_t arraySize = array.size(); // Get the total number of elements in the array
size_t currentIndex = 0; // Track the current index
for (JsonVariant element : array) {
if (element.is<int>()) {
csvOutput += String(element.as<int>());
} else if (element.is<float>()) {
csvOutput += doubleToString(element.as<double>(), nr_decimals, true);
} else if (element.is<const char *>()) {
csvOutput += String(element.as<const char *>());
} else {
csvOutput += F("unknown");
}
// Add a comma unless it's the last element
currentIndex++;
if (currentIndex < arraySize) {
csvOutput += ',';
}
}
} else {
csvOutput += F("unknown");
}
} else {
csvOutput += F("null"); // Indicate missing value
csvOutput += val;
csvOutput += ',';
}
csvOutput += ',';
# endif // if FEATURE_JSON_PARSE
}
keyFile.close();
if (!csvOutput.isEmpty()) { // If there is nothing to show don't create an event
if (csvOutput.charAt(csvOutput.length() - 1) == ',') {
// Check if the last character is a comma
csvOutput.remove(csvOutput.length() - 1); // Remove the last character
}
// Log the results
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, strformat(F("Successfully processed %d out of %d keys"), successfullyProcessedCount, keyCount));
}
eventQueue.addMove(strformat(F("JsonReply%s%s=%s"),
numJson != 0 ? "#" : "",
toStringNoZero(numJson).c_str(),
csvOutput.c_str()));
}
}
# endif // if FEATURE_JSON_EVENT
void eventFromResponse(const String& host, const int& httpCode, const String& uri, ESPEasy_HTTPClient& http, const int& parseJson) {
@@ -269,188 +455,7 @@ void eventFromResponse(const String& host, const int& httpCode, const String& ur
// ------------------------------------------------------------------------------------------- JSONevent Key processing
# if FEATURE_JSON_EVENT
void readAndProcessJsonKeys(DynamicJsonDocument *root, int numJson) {
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
int nr_decimals = ESPEASY_DOUBLE_NR_DECIMALS;
# else // ifdef FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
int nr_decimals = ESPEASY_FLOAT_NR_DECIMALS;
# endif // ifdef FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
// Open the `json.keys` file
# ifdef ESP8266
const String fileName = F("json.keys");
# else // ifdef ESP8266
const String fileName = F("/json.keys");
# endif // ifdef ESP8266
if (!fileExists(fileName)) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
addLogMove(LOG_LEVEL_ERROR, strformat(F("%s does not exist!"), fileName.c_str()));
}
return;
}
File keyFile = ESPEASY_FS.open(fileName, "r");
int keyCount = 0;
int successfullyProcessedCount = 0; // Counter for successfully processed keys
String csvOutput; // Collect values as a CSV string
while (keyFile.available()) {
String key = keyFile.readStringUntil('\n');
key.trim(); // Remove extra spaces or newlines
if (key.isEmpty()) {
continue;
}
int keyNumber = 0;
// Extract the number prefix (before the first dot)
if (key.indexOf(':') != -1) {
keyNumber = key.substring(0, key.indexOf(':')).toInt();
key = key.substring(key.indexOf(':') + 1);
}
// Only process keys that match the filterNumber (or process all if no match)
if ((numJson > 0) && (keyNumber != numJson)) {
continue; // Skip this key if it doesn't match the filter number
}
keyCount++;
if (keyCount > MAX_KEYS) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
addLogMove(LOG_LEVEL_ERROR, strformat(F("Warning: More than %d keys in %s"), MAX_KEYS, fileName.c_str()));
}
}
# if FEATURE_JSON_PARSE
const String val = getJsonValue(root, key, false); // Return arrays and objects as csv, _not_ JSON formatted
if (!val.isEmpty()) {
successfullyProcessedCount++;
csvOutput += val;
csvOutput += ',';
}
# else // if FEATURE_JSON_PARSE
// Process the key and navigate the JSON
JsonVariant value = *root;
size_t start = 0, end;
while ((end = key.indexOf('.', start)) != (unsigned int)-1) {
String part = key.substring(start, end);
start = end + 1;
// Look for an array e.g., "result[0]" → object "result", index 0
int bracketStart = part.indexOf('[');
if (bracketStart != -1) {
String objectName = part.substring(0, bracketStart);
String indexStr = part.substring(bracketStart + 1, part.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName]; // Access the object
}
if (value.is<JsonArray>()) {
int index = indexStr.toInt();
value = value[index];
} else {
value = value[indexStr]; // fallback if not actually array
}
} else {
// Normal object access without array
value = value[part];
}
if (value.isNull()) {
break; // Key path is invalid
}
}
if (!value.isNull()) {
successfullyProcessedCount++;
String lastPart = key.substring(start);
int bracketStart = lastPart.indexOf('[');
if (bracketStart != -1) {
String objectName = lastPart.substring(0, bracketStart);
String indexStr = lastPart.substring(bracketStart + 1, lastPart.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName];
}
if (value.is<JsonArray>()) {
value = value[indexStr.toInt()];
} else {
value = value[indexStr];
}
} else {
value = value[lastPart];
}
}
// Append the value to the CSV string if it exists
if (!value.isNull()) {
if (value.is<int>()) {
csvOutput += String(value.as<int>());
} else if (value.is<float>()) {
csvOutput += doubleToString(value.as<double>(), nr_decimals, true);
} else if (value.is<const char *>()) {
csvOutput += String(value.as<const char *>());
} else if (value.is<JsonArray>()) {
// If the value is an array, iterate over its elements
JsonArray array = value.as<JsonArray>();
size_t arraySize = array.size(); // Get the total number of elements in the array
size_t currentIndex = 0; // Track the current index
for (JsonVariant element : array) {
if (element.is<int>()) {
csvOutput += String(element.as<int>());
} else if (element.is<float>()) {
csvOutput += doubleToString(element.as<double>(), nr_decimals, true);
} else if (element.is<const char *>()) {
csvOutput += String(element.as<const char *>());
} else {
csvOutput += F("unknown");
}
// Add a comma unless it's the last element
currentIndex++;
if (currentIndex < arraySize) {
csvOutput += ',';
}
}
} else {
csvOutput += F("unknown");
}
} else {
csvOutput += F("null"); // Indicate missing value
csvOutput += val;
csvOutput += ',';
}
csvOutput += ',';
# endif // if FEATURE_JSON_PARSE
}
keyFile.close();
if (!csvOutput.isEmpty()) { // If there is nothing to show don't create an event
if (csvOutput.charAt(csvOutput.length() - 1) == ',') {
// Check if the last character is a comma
csvOutput.remove(csvOutput.length() - 1); // Remove the last character
}
// Log the results
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, strformat(F("Successfully processed %d out of %d keys"), successfullyProcessedCount, keyCount));
}
eventQueue.addMove(strformat(F("JsonReply%s%s=%s"),
numJson != 0 ? "#" : "",
toStringNoZero(numJson).c_str(),
csvOutput.c_str()));
}
}
// ------------------------------------------------------------------------------------------- JSONevent Helper
UriParseResult parseUriPath(const String& path) {
-6
View File
@@ -28,12 +28,6 @@ void eventFromResponse(const String& host,
# if FEATURE_JSON_EVENT
/**
* @brief Reads and processes keys from a json.keys file and navigates the JSON document.
*/
void readAndProcessJsonKeys(DynamicJsonDocument*root,
int numJson);
/**
* @brief Result of parsing a URI for JSON flag.
*/
+4 -4
View File
@@ -709,7 +709,7 @@ void readBootCause() {
/********************************************************************************************\
Hardware specific configurations
\*********************************************************************************************/
const __FlashStringHelper* getDeviceModelBrandString(DeviceModel model) {
static const __FlashStringHelper* getDeviceModelBrandString(DeviceModel model) {
switch (model) {
case DeviceModel::DeviceModel_Sonoff_Basic:
case DeviceModel::DeviceModel_Sonoff_TH1x:
@@ -746,7 +746,7 @@ const __FlashStringHelper* getDeviceModelBrandString(DeviceModel model) {
return F("");
}
const __FlashStringHelper* getDeviceModelTypeString(DeviceModel model)
static const __FlashStringHelper* getDeviceModelTypeString(DeviceModel model)
{
switch (model) {
#if defined(ESP8266) && !defined(LIMIT_BUILD_SIZE)
@@ -862,7 +862,7 @@ void setFactoryDefault(DeviceModel model) {
/********************************************************************************************\
Add pre defined plugins and rules.
\*********************************************************************************************/
void addSwitchPlugin(taskIndex_t taskIndex, int gpio, const String& name, bool activeLow) {
static void addSwitchPlugin(taskIndex_t taskIndex, int gpio, const String& name, bool activeLow) {
setTaskDevice_to_TaskIndex(PLUGIN_GPIO, taskIndex);
const int pins[] = { gpio, -1, -1 };
@@ -900,7 +900,7 @@ void addPredefinedPlugins(const GpioFactorySettingsStruct& gpio_settings) {
}
}
void addButtonRelayRule(uint8_t buttonNumber, int relay_gpio) {
static void addButtonRelayRule(uint8_t buttonNumber, int relay_gpio) {
Settings.UseRules = true;
String fileName;
-9
View File
@@ -92,8 +92,6 @@ void readBootCause();
/********************************************************************************************\
Hardware specific configurations
\*********************************************************************************************/
const __FlashStringHelper* getDeviceModelBrandString(DeviceModel model);
String getDeviceModelString(DeviceModel model);
bool modelMatchingFlashSize(DeviceModel model);
@@ -103,15 +101,8 @@ void setFactoryDefault(DeviceModel model);
/********************************************************************************************\
Add pre defined plugins and rules.
\*********************************************************************************************/
void addSwitchPlugin(taskIndex_t taskIndex,
int gpio,
const String& name,
bool activeLow);
void addPredefinedPlugins(const GpioFactorySettingsStruct& gpio_settings);
void addButtonRelayRule(uint8_t buttonNumber,
int relay_gpio);
void addPredefinedRules(const GpioFactorySettingsStruct& gpio_settings);
+59 -54
View File
@@ -86,59 +86,7 @@ void initI2C() {
I2CSelectHighClockSpeed(0); // Select first interface by default
}
void I2CSelectHighClockSpeed(uint8_t i2cBus) {
const uint32_t clockSpeed = Settings.getI2CClockSpeed(i2cBus);
I2CSelectClockSpeed(i2cBus, clockSpeed);
}
void I2CSelectLowClockSpeed(uint8_t i2cBus) {
const uint32_t clockSpeed = Settings.getI2CClockSpeedSlow(i2cBus);
I2CSelectClockSpeed(i2cBus, clockSpeed);
}
void I2CSelect_Max100kHz_ClockSpeed(uint8_t i2cBus) {
const uint32_t clockSpeed = Settings.getI2CClockSpeed(i2cBus);
const uint32_t clockSpeed_Slow = Settings.getI2CClockSpeedSlow(i2cBus);
if (clockSpeed <= 100000) {
I2CSelectHighClockSpeed(i2cBus);
} else if (clockSpeed_Slow <= 100000) {
I2CSelectLowClockSpeed(i2cBus);
} else {
I2CSelectClockSpeed(i2cBus, 100000);
}
}
void I2CSelectClockSpeed(uint8_t i2cBus, uint32_t clockFreq) {
const int8_t i2c_sda = Settings.getI2CSdaPin(i2cBus);
const int8_t i2c_scl = Settings.getI2CSclPin(i2cBus);
const uint32_t ClockStretchLimit = Settings.getI2CClockStretch(i2cBus);
I2CBegin(i2c_sda, i2c_scl, clockFreq, ClockStretchLimit);
}
void I2CForceResetBus_swap_pins(uint8_t i2cBus, uint8_t address) {
#if FEATURE_CLEAR_I2C_STUCK
if (!Settings.EnableClearHangingI2Cbus()) { return; }
#endif // if FEATURE_CLEAR_I2C_STUCK
// As a final work-around, we temporary swap SDA and SCL, perform a scan and return pin order.
const int8_t i2c_sda = Settings.getI2CSdaPin(i2cBus);
const int8_t i2c_scl = Settings.getI2CSclPin(i2cBus);
const uint32_t ClockStretchLimit = Settings.getI2CClockStretch(i2cBus);
I2CBegin(i2c_scl, i2c_sda, 100000, ClockStretchLimit);
I2C_wakeup(address);
delay(1);
// Now we switch back to the correct pins
I2CSelectClockSpeed(i2cBus, 100000);
}
void I2CBegin(int8_t sda, int8_t scl, uint32_t clockFreq, uint32_t clockStretch) {
static void I2CBegin(int8_t sda, int8_t scl, uint32_t clockFreq, uint32_t clockStretch) {
#ifdef ESP32
uint32_t lastI2CClockSpeed = Wire.getClock();
#else // ifdef ESP32
@@ -209,6 +157,61 @@ void I2CBegin(int8_t sda, int8_t scl, uint32_t clockFreq, uint32_t clockStretch)
}
}
static void I2CSelectClockSpeed(uint8_t i2cBus, uint32_t clockFreq) {
const int8_t i2c_sda = Settings.getI2CSdaPin(i2cBus);
const int8_t i2c_scl = Settings.getI2CSclPin(i2cBus);
const uint32_t ClockStretchLimit = Settings.getI2CClockStretch(i2cBus);
I2CBegin(i2c_sda, i2c_scl, clockFreq, ClockStretchLimit);
}
void I2CSelectHighClockSpeed(uint8_t i2cBus) {
const uint32_t clockSpeed = Settings.getI2CClockSpeed(i2cBus);
I2CSelectClockSpeed(i2cBus, clockSpeed);
}
void I2CSelectLowClockSpeed(uint8_t i2cBus) {
const uint32_t clockSpeed = Settings.getI2CClockSpeedSlow(i2cBus);
I2CSelectClockSpeed(i2cBus, clockSpeed);
}
void I2CSelect_Max100kHz_ClockSpeed(uint8_t i2cBus) {
const uint32_t clockSpeed = Settings.getI2CClockSpeed(i2cBus);
const uint32_t clockSpeed_Slow = Settings.getI2CClockSpeedSlow(i2cBus);
if (clockSpeed <= 100000) {
I2CSelectHighClockSpeed(i2cBus);
} else if (clockSpeed_Slow <= 100000) {
I2CSelectLowClockSpeed(i2cBus);
} else {
I2CSelectClockSpeed(i2cBus, 100000);
}
}
void I2CForceResetBus_swap_pins(uint8_t i2cBus, uint8_t address) {
#if FEATURE_CLEAR_I2C_STUCK
if (!Settings.EnableClearHangingI2Cbus()) { return; }
#endif // if FEATURE_CLEAR_I2C_STUCK
// As a final work-around, we temporary swap SDA and SCL, perform a scan and return pin order.
const int8_t i2c_sda = Settings.getI2CSdaPin(i2cBus);
const int8_t i2c_scl = Settings.getI2CSclPin(i2cBus);
const uint32_t ClockStretchLimit = Settings.getI2CClockStretch(i2cBus);
I2CBegin(i2c_scl, i2c_sda, 100000, ClockStretchLimit);
I2C_wakeup(address);
delay(1);
// Now we switch back to the correct pins
I2CSelectClockSpeed(i2cBus, 100000);
}
#if FEATURE_I2CMULTIPLEXER
// Check if the I2C Multiplexer is enabled
@@ -218,6 +221,7 @@ bool isI2CMultiplexerEnabled(uint8_t i2cBus) {
}
// Reset the I2C Multiplexer, if a pin is assigned for that. Pulled to low to force a reset.
/*
void I2CMultiplexerReset(uint8_t i2cBus) {
const uint8_t Multiplexer_ResetPin = Settings.getI2CMultiplexerResetPin(i2cBus);
@@ -227,9 +231,10 @@ void I2CMultiplexerReset(uint8_t i2cBus) {
digitalWrite(Multiplexer_ResetPin, HIGH);
}
}
*/
// Shift the bit in the right position when selecting a single channel
uint8_t I2CMultiplexerShiftBit(uint8_t i2cBus, uint8_t i) {
static uint8_t I2CMultiplexerShiftBit(uint8_t i2cBus, uint8_t i) {
uint8_t toWrite = 0;
const int8_t Multiplexer_Type = Settings.getI2CMultiplexerType(i2cBus);
+1 -9
View File
@@ -12,20 +12,12 @@ void initI2C();
void I2CSelectHighClockSpeed(uint8_t i2cBus);
void I2CSelectLowClockSpeed(uint8_t i2cBus);
void I2CSelect_Max100kHz_ClockSpeed(uint8_t i2cBus);
void I2CSelectClockSpeed(uint8_t i2cBus,
uint32_t clockFreq);
void I2CForceResetBus_swap_pins(uint8_t i2cBus,
uint8_t address);
void I2CBegin(int8_t sda,
int8_t scl,
uint32_t clockFreq,
uint32_t clockStretch);
#if FEATURE_I2CMULTIPLEXER
bool isI2CMultiplexerEnabled(uint8_t i2cBus);
uint8_t I2CMultiplexerShiftBit(uint8_t i2cBus, uint8_t i);
void I2CMultiplexerSelectByBusAndMux(uint8_t i2cBus,
bool singleMulti,
int muxPort);
@@ -40,7 +32,7 @@ void SetI2CMultiplexer(uint8_t i2cBus,
uint8_t I2CMultiplexerMaxChannels(uint8_t i2cBus);
void I2CMultiplexerReset(uint8_t i2cBus);
// void I2CMultiplexerReset(uint8_t i2cBus);
bool I2CMultiplexerPortSelectedForTask(taskIndex_t taskIndex);
#endif // if FEATURE_I2CMULTIPLEXER
+1 -1
View File
@@ -51,7 +51,7 @@ void initAnalogWrite()
// Match frequency and resolution and optionally adjust duty accordingly
// @return adjusted duty cycle
uint32_t adapt_ledc_frequency_resolution_duty(uint32_t& frequency, uint8_t& resolution, uint32_t duty = 0)
static uint32_t adapt_ledc_frequency_resolution_duty(uint32_t& frequency, uint8_t& resolution, uint32_t duty = 0)
{
while ((40000000u >> resolution) < frequency && resolution > 1) {
--resolution;
@@ -38,7 +38,7 @@ uint8_t temprature_sens_read();
# if defined(ESP32_CLASSIC)
esp_err_t do_read_internal_temperature(float& celsius) {
static esp_err_t do_read_internal_temperature(float& celsius) {
esp_err_t result = ESP_FAIL;
uint8_t raw = 128u;
int8_t retries = 2;
@@ -64,7 +64,7 @@ esp_err_t do_read_internal_temperature(float& celsius) {
# elif defined(ESP32C2) || defined(ESP32C3) || defined(ESP32C5) || defined(ESP32C6) || defined(ESP32C61) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32P4)
esp_err_t do_read_internal_temperature(float& celsius) {
static esp_err_t do_read_internal_temperature(float& celsius) {
esp_err_t result = ESP_FAIL;
celsius = 0.0f; // Make sure it is initialized and within the default range.
+72 -76
View File
@@ -12,82 +12,7 @@
#if FEATURE_JSON_PARSE
# include "../Helpers/StringConverter.h"
// Private for now
String getJsonValue(JsonVariant element,
bool asJson);
String getJsonValue(DynamicJsonDocument *root,
String key,
bool asJson) {
// Process the key and navigate the JSON
JsonVariant value = *root;
size_t start = 0;
size_t end;
String result;
while ((end = key.indexOf('.', start)) != -1) {
const String part = key.substring(start, end);
start = end + 1;
// Look for an array e.g., "result[0]" → object "result", index 0
const int bracketStart = part.indexOf('[');
if (bracketStart != -1) {
const String objectName = part.substring(0, bracketStart);
const String indexStr = part.substring(bracketStart + 1, part.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName]; // Access the object
}
if (value.is<JsonArray>()) {
value = value[indexStr.toInt()];
} else {
value = value[indexStr]; // fallback if not actually array
}
} else {
// Normal object access without array
value = value[part];
}
if (value.isNull()) {
break; // Key path is invalid
}
}
if (!value.isNull()) {
const String lastPart = key.substring(start);
const int bracketStart = lastPart.indexOf('[');
if (bracketStart != -1) {
const String objectName = lastPart.substring(0, bracketStart);
const String indexStr = lastPart.substring(bracketStart + 1, lastPart.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName];
}
if (value.is<JsonArray>()) {
value = value[indexStr.toInt()];
} else {
value = value[indexStr];
}
} else {
value = value[lastPart];
}
}
// Append the value to the CSV string if it exists
if (!value.isNull()) {
result += getJsonValue(value, asJson);
} else {
result += F("null");
}
return result;
}
String getJsonValue(JsonVariant value, bool asJson) {
static String getJsonValue(JsonVariant value, bool asJson) {
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
const int nr_decimals = ESPEASY_DOUBLE_NR_DECIMALS;
# else // ifdef FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
@@ -170,4 +95,75 @@ String getJsonValue(JsonVariant value, bool asJson) {
return result;
}
String getJsonValue(DynamicJsonDocument *root,
String key,
bool asJson) {
// Process the key and navigate the JSON
JsonVariant value = *root;
size_t start = 0;
size_t end;
String result;
while ((end = key.indexOf('.', start)) != -1) {
const String part = key.substring(start, end);
start = end + 1;
// Look for an array e.g., "result[0]" → object "result", index 0
const int bracketStart = part.indexOf('[');
if (bracketStart != -1) {
const String objectName = part.substring(0, bracketStart);
const String indexStr = part.substring(bracketStart + 1, part.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName]; // Access the object
}
if (value.is<JsonArray>()) {
value = value[indexStr.toInt()];
} else {
value = value[indexStr]; // fallback if not actually array
}
} else {
// Normal object access without array
value = value[part];
}
if (value.isNull()) {
break; // Key path is invalid
}
}
if (!value.isNull()) {
const String lastPart = key.substring(start);
const int bracketStart = lastPart.indexOf('[');
if (bracketStart != -1) {
const String objectName = lastPart.substring(0, bracketStart);
const String indexStr = lastPart.substring(bracketStart + 1, lastPart.indexOf(']', bracketStart));
if (objectName.length() > 0) {
value = value[objectName];
}
if (value.is<JsonArray>()) {
value = value[indexStr.toInt()];
} else {
value = value[indexStr];
}
} else {
value = value[lastPart];
}
}
// Append the value to the CSV string if it exists
if (!value.isNull()) {
result += getJsonValue(value, asJson);
} else {
result += F("null");
}
return result;
}
#endif // if FEATURE_JSON_PARSE
+1 -1
View File
@@ -15,7 +15,7 @@
#if FEATURE_SD
void addToSDLog(uint8_t logLevel, const String& str)
static void addToSDLog(uint8_t logLevel, const String& str)
{
if (!str.isEmpty() && loglevelActiveFor(LOG_TO_SDCARD, logLevel)) {
String logName = patch_fname(F("log.txt"));
+79 -55
View File
@@ -92,34 +92,10 @@ void etharp_gratuitous_r(struct netif *netif) { tcpip_callback_with_block((t
#if FEATURE_ESPEASY_P2P
/*********************************************************************************************\
Send event using UDP message
\*********************************************************************************************/
void SendUDPCommand(uint8_t destUnit, const char *data, uint8_t dataLength)
{
if (!NetworkConnected(10)) {
return;
}
if (destUnit != 0)
{
sendUDP(destUnit, (const uint8_t *)data, dataLength);
delay(10);
} else {
for (auto it = Nodes.begin(); it != Nodes.end(); ++it) {
if (it->first != Settings.Unit) {
sendUDP(it->first, (const uint8_t *)data, dataLength);
delay(10);
}
}
}
delay(50);
}
/*********************************************************************************************\
Send UDP message to specific unit (unit 255=broadcast)
\*********************************************************************************************/
void sendUDP(uint8_t unit, const uint8_t *data, uint8_t size)
static void sendUDP(uint8_t unit, const uint8_t *data, uint8_t size)
{
if (!NetworkConnected(10)) {
return;
@@ -151,6 +127,32 @@ void sendUDP(uint8_t unit, const uint8_t *data, uint8_t size)
delay(0);
}
/*********************************************************************************************\
Send event using UDP message
\*********************************************************************************************/
void SendUDPCommand(uint8_t destUnit, const char *data, uint8_t dataLength)
{
if (!NetworkConnected(10)) {
return;
}
if (destUnit != 0)
{
sendUDP(destUnit, (const uint8_t *)data, dataLength);
delay(10);
} else {
for (auto it = Nodes.begin(); it != Nodes.end(); ++it) {
if (it->first != Settings.Unit) {
sendUDP(it->first, (const uint8_t *)data, dataLength);
delay(10);
}
}
}
delay(50);
}
/*********************************************************************************************\
Update UDP port (ESPEasy propiertary protocol)
\*********************************************************************************************/
@@ -709,7 +711,7 @@ bool SSDP_begin() {
/********************************************************************************************\
Send SSDP messages (notify & responses)
\*********************************************************************************************/
void SSDP_send(uint8_t method) {
static void SSDP_send(uint8_t method) {
uint32_t ip = ESPEasy::net::NetworkLocalIP();
// FIXME TD-er: Why create String objects of these flashstrings?
@@ -942,12 +944,14 @@ void SSDP_update() {
// ********************************************************************************
// Return subnet range of active network interface.
// ********************************************************************************
/*
bool getSubnetRange(IPAddress& low, IPAddress& high)
{
low = ESPEasy::net::NetworkID();
high = ESPEasy::net::NetworkBroadcast();
return true;
}
*/
// ********************************************************************************
// Functions to test and handle network/client connectivity.
@@ -956,7 +960,7 @@ bool getSubnetRange(IPAddress& low, IPAddress& high)
#ifdef CORE_POST_2_5_0
# include <AddrList.h>
#endif // ifdef CORE_POST_2_5_0
/*
bool hasIPaddr() {
if (useStaticIP()) { return true; }
@@ -965,12 +969,12 @@ bool hasIPaddr() {
for (auto addr : addrList) {
if ((configured = (!addr.isLocal() && (addr.ifnumber() == STATION_IF)))) {
/*
ESPEASY_SERIAL_CONSOLE_PORT.printf("STA: IF='%s' hostname='%s' addr= %s\n",
addr.ifname().c_str(),
addr.ifhostname(),
addr.toString().c_str());
*/
// ESPEASY_SERIAL_CONSOLE_PORT.printf("STA: IF='%s' hostname='%s' addr= %s\n",
// addr.ifname().c_str(),
// addr.ifhostname(),
// addr.toString().c_str());
break;
}
}
@@ -979,7 +983,7 @@ bool hasIPaddr() {
return WiFi.isConnected();
#endif // ifdef CORE_POST_2_5_0
}
*/
bool useStaticIP() {
#if FEATURE_ETHERNET
@@ -1120,7 +1124,7 @@ bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port, uint32_t tim
#endif // FEATURE_HTTP_CLIENT
void scrubDNS() {
static void scrubDNS() {
/*
#if FEATURE_ETHERNET
@@ -1227,7 +1231,7 @@ bool resolveHostByName(const char *aHostname, IPAddress& aResult, uint32_t timeo
uint32_t start = millis();
for (int attempt = 0;
attempt < 2 && !resolvedIP && timePassedSince(start) < timeout_ms;
attempt < 2 && !resolvedIP && timePassedSince(start) < static_cast<int32_t>(timeout_ms);
++attempt) {
#if defined(ARDUINO_ESP8266_RELEASE_2_3_0)
@@ -1309,7 +1313,7 @@ void sendGratuitousARP() {
#endif // ifdef SUPPORT_ARP
}
bool splitHostPortString(const String& hostPortString, String& host, uint16_t& port) {
static bool splitHostPortString(const String& hostPortString, String& host, uint16_t& port) {
port = 80; // Some default
int index_colon = hostPortString.indexOf(':');
@@ -1383,7 +1387,10 @@ String splitURL(const String& fullURL, String& user, String& pass, String& host,
return fullURL.substring(endhost);
}
String joinURL(const String& user, const String& pass, const String& host, uint16_t& port, const String& uri, const String& protocol)
# if defined(CORE_POST_2_6_0) || defined(ESP32)
# if FEATURE_TLS
static String joinURL(const String& user, const String& pass, const String& host, uint16_t& port, const String& uri, const String& protocol)
{
String fullURL;
if (protocol.isEmpty()) {
@@ -1410,8 +1417,10 @@ String joinURL(const String& user, const String& pass, const String& host, uint1
return fullURL;
}
#endif
#endif
String get_user_agent_string() {
static String get_user_agent_string() {
static unsigned int agent_size = 20;
String userAgent;
@@ -1426,7 +1435,7 @@ String get_user_agent_string() {
return userAgent;
}
bool splitHeaders(int& strpos, const String& multiHeaders, String& name, String& value) {
static bool splitHeaders(int& strpos, const String& multiHeaders, String& name, String& value) {
if (strpos < 0) {
return false;
}
@@ -1450,7 +1459,7 @@ bool splitHeaders(int& strpos, const String& multiHeaders, String& name, String&
return true;
}
String extractParam(const String& authReq, const String& param, const char delimit) {
static String extractParam(const String& authReq, const String& param, const char delimit) {
int _begin = authReq.indexOf(param);
if (_begin == -1) { return EMPTY_STRING; }
@@ -1459,7 +1468,7 @@ String extractParam(const String& authReq, const String& param, const char delim
#if FEATURE_HTTP_CLIENT
String getCNonce(const int len) {
static String getCNonce(const int len) {
static const char alphanum[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
@@ -1473,12 +1482,12 @@ String getCNonce(const int len) {
return s;
}
String getDigestAuth(const String& authReq,
const String& username,
const String& password,
const String& method,
const String& uri,
unsigned int counter) {
static String getDigestAuth(const String& authReq,
const String& username,
const String& password,
const String& method,
const String& uri,
unsigned int counter) {
// extracting required parameters for RFC 2069 simpler Digest
const String realm = extractParam(authReq, F("realm=\""), '"');
const String nonce = extractParam(authReq, F("nonce=\""), '"');
@@ -1524,7 +1533,7 @@ String getDigestAuth(const String& authReq,
# if !defined(BUILD_NO_DEBUG) || defined(ESP32)
void log_http_result(const ESPEasy_HTTPClient& http,
static void log_http_result(const ESPEasy_HTTPClient& http,
const String & logIdentifier,
const String & host,
const String & HttpMethod,
@@ -1564,8 +1573,10 @@ void log_http_result(const ESPEasy_HTTPClient& http,
}
# endif // ifndef BUILD_NO_DEBUG
int http_authenticate(const String& logIdentifier,
// Initiate the HTTP connection.
// Also try to authenticate using either Basic auth or Digest.
// @retval HTTP return code.
static int http_authenticate(const String& logIdentifier,
WiFiClient & client,
ESPEasy_HTTPClient & http,
uint16_t timeout,
@@ -1728,7 +1739,7 @@ int http_authenticate(const String& logIdentifier,
http.end();
# if defined(CORE_POST_2_6_0) || defined(ESP32)
# if FEATURE_TLS
const String fullURL = joinURL(user, pass, host, port, uri);
const String fullURL = joinURL(user, pass, host, port, uri, EMPTY_STRING);
if (fullURL.startsWith(F("https")))
http.begin(fullURL, nullptr); // HTTPS
else
@@ -1916,7 +1927,7 @@ bool downloadFile(const String& url, String file_save) {
// User and Pass may be updated if they occur in the hostname part.
// Thus have to be copied instead of const reference.
bool start_downloadFile(WiFiClient & client,
static bool start_downloadFile(WiFiClient & client,
ESPEasy_HTTPClient & http,
const String& url,
String & file_save,
@@ -2003,7 +2014,12 @@ bool downloadFile(const String& url, String file_save, const String& user, const
uint32_t timeout = millis() + DOWNLOAD_FILE_TIMEOUT;
// get tcp stream
WiFiClient *stream = &client;
WiFiClient *stream = http.getStreamPtr();
if (stream == nullptr) {
stream = &client;
}
// read all data from server
while (http.connected() && (len > 0 || len == -1)) {
@@ -2023,6 +2039,8 @@ bool downloadFile(const String& url, String file_save, const String& user, const
addLog(LOG_LEVEL_ERROR, error);
http.end();
client.stop();
f.close();
tryDeleteFile(file_save);
return false;
}
bytesWritten += c;
@@ -2036,6 +2054,8 @@ bool downloadFile(const String& url, String file_save, const String& user, const
delay(0);
http.end();
client.stop();
f.close();
tryDeleteFile(file_save);
return false;
}
delay(0);
@@ -2102,7 +2122,11 @@ bool downloadFirmware(const String& url, String& file_save, String& user, String
uint32_t timeout = millis() + DOWNLOAD_FILE_TIMEOUT;
// get tcp stream
WiFiClient *stream = &client;
WiFiClient *stream = http.getStreamPtr();
if (stream == nullptr) {
stream = &client;
}
while (error.isEmpty() && http.connected() && (len > 0 || len == -1)) {
// read up to downloadBuffSize at a time.
+2 -38
View File
@@ -94,11 +94,6 @@ uint8_t getTypeForUnit(uint8_t unit);
\*********************************************************************************************/
String getTypeStringForUnit(uint8_t unit);
/*********************************************************************************************\
Send UDP message to specific unit (unit 255=broadcast)
\*********************************************************************************************/
void sendUDP(uint8_t unit, const uint8_t *data, uint8_t size);
/*********************************************************************************************\
Refresh aging for remote units, drop if too old...
\*********************************************************************************************/
@@ -152,10 +147,6 @@ extern uint32_t _notify_time;
\*********************************************************************************************/
bool SSDP_begin();
/********************************************************************************************\
Send SSDP messages (notify & responses)
\*********************************************************************************************/
void SSDP_send(uint8_t method);
/********************************************************************************************\
SSDP message processing
@@ -169,7 +160,7 @@ void SSDP_update();
// ********************************************************************************
// Return subnet range of WiFi.
// ********************************************************************************
bool getSubnetRange(IPAddress& low, IPAddress& high);
//bool getSubnetRange(IPAddress& low, IPAddress& high);
// ********************************************************************************
// Functions to test and handle network/client connectivity.
@@ -180,7 +171,7 @@ bool getSubnetRange(IPAddress& low, IPAddress& high);
#endif // ifdef CORE_POST_2_5_0
bool hasIPaddr();
//bool hasIPaddr();
bool useStaticIP();
@@ -195,7 +186,6 @@ bool connectClient(WiFiClient& client, const char *hostname, uint16_t port, uint
bool connectClient(WiFiClient& client, IPAddress ip, uint16_t port, uint32_t timeout_ms = 100);
#endif // FEATURE_HTTP_CLIENT
void scrubDNS();
bool IPAddressSet(const IPAddress& ip);
@@ -214,8 +204,6 @@ bool beginWiFiUDP_randomPort(WiFiUDP& udp);
void sendGratuitousARP();
bool splitHostPortString(const String& hostPortString, String& host, uint16_t& port);
// Split the username and password from a string like this:
// username:password@hostname:portnr
// @param hostPortString The string to parse
@@ -230,32 +218,8 @@ bool splitUserPass_HostPortString(const String& hostPortString, String& user, St
// Return value is everything after the hostname:port section (including /)
String splitURL(const String& fullURL, String& user, String& pass, String& host, uint16_t& port, String& file, String& protocol);
String joinURL(const String& user, const String& pass, const String& host, uint16_t& port, const String& uri, const String& protocol = EMPTY_STRING );
#if FEATURE_HTTP_CLIENT
// Initiate the HTTP connection.
// Also try to authenticate using either Basic auth or Digest.
// @retval HTTP return code.
int http_authenticate(const String& logIdentifier,
WiFiClient & client,
ESPEasy_HTTPClient & http,
uint16_t timeout,
const String& user,
const String& pass,
const String& host,
uint16_t port,
const String& protocol,
# if FEATURE_JSON_EVENT
String uri,
# else // if FEATURE_JSON_EVENT
const String& uri,
# endif // if FEATURE_JSON_EVENT
const String& HttpMethod,
const String& header,
const String& postStr,
bool must_check_reply);
String send_via_http(const String& logIdentifier,
uint16_t timeout,
+2 -2
View File
@@ -354,7 +354,7 @@ void scheduleNextMQTTdelayQueue() {
}
}
void schedule_all_MQTTimport_tasks() {
static void schedule_all_MQTTimport_tasks() {
constexpr pluginID_t PLUGIN_MQTT_IMPORT(PLUGIN_ID_MQTT_IMPORT);
deviceIndex_t DeviceIndex = getDeviceIndex(PLUGIN_MQTT_IMPORT); // Check if P037_MQTTimport is present in the build
@@ -566,7 +566,7 @@ void logTimerStatistics() {
/********************************************************************************************\
Clean up all before going to sleep or reboot.
\*********************************************************************************************/
void flushAndDisconnectAllClients() {
static void flushAndDisconnectAllClients() {
if (anyControllerEnabled()) {
#if FEATURE_MQTT
bool mqttControllerEnabled = validControllerIndex(firstEnabledMQTT_ControllerIndex());
-1
View File
@@ -31,7 +31,6 @@ void runEach30Seconds();
#if FEATURE_MQTT
void scheduleNextMQTTdelayQueue();
void schedule_all_MQTTimport_tasks();
void processMQTTdelayQueue();
+3 -3
View File
@@ -10,7 +10,7 @@
Test for common mistake
Return true if mistake was found (and corrected)
\*********************************************************************************************/
bool rules_replace_common_mistakes(const String& from, const String& to, String& line)
static bool rules_replace_common_mistakes(const String& from, const String& to, String& line)
{
if (line.indexOf(from) == -1) {
return false; // Nothing replaced
@@ -37,7 +37,7 @@ bool rules_replace_common_mistakes(const String& from, const String& to, String&
Check for common mistakes
Return true if nothing strange found
\*********************************************************************************************/
bool check_rules_line_user_errors(String& line)
static bool check_rules_line_user_errors(String& line)
{
bool res = true;
@@ -56,7 +56,7 @@ bool check_rules_line_user_errors(String& line)
Strip comment from the line.
Return true when comment was stripped.
\*********************************************************************************************/
bool rules_strip_trailing_comments(String& line)
static bool rules_strip_trailing_comments(String& line)
{
// Strip trailing comments
int comment = line.indexOf(F("//"));
+292 -213
View File
@@ -8,6 +8,76 @@
#include "../Helpers/Numerical.h"
#include "../Helpers/StringConverter.h"
static const __FlashStringHelper* toString(UnaryOperator op)
{
switch (op)
{
case UnaryOperator::Not:
break; // No need to replace
case UnaryOperator::Log:
return F("log");
case UnaryOperator::Ln:
return F("ln");
case UnaryOperator::Abs:
return F("abs");
case UnaryOperator::Exp:
return F("exp");
case UnaryOperator::Sqrt:
return F("sqrt");
case UnaryOperator::Sq:
return F("sq");
case UnaryOperator::Round:
return F("round");
case UnaryOperator::Sin:
return F("sin");
case UnaryOperator::Sin_d:
return F("sin_d");
case UnaryOperator::Cos:
return F("cos");
case UnaryOperator::Cos_d:
return F("cos_d");
case UnaryOperator::Tan:
return F("tan");
case UnaryOperator::Tan_d:
return F("tan_d");
case UnaryOperator::ArcSin:
return F("asin");
case UnaryOperator::ArcSin_d:
return F("asin_d");
case UnaryOperator::ArcCos:
return F("acos");
case UnaryOperator::ArcCos_d:
return F("acos_d");
case UnaryOperator::ArcTan:
return F("atan");
case UnaryOperator::ArcTan_d:
return F("atan_d");
case UnaryOperator::Map:
return F("map");
case UnaryOperator::MapC:
return F("mapc");
}
return F("");
}
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
static const __FlashStringHelper* toString(BinaryOperator op)
{
switch (op)
{
case BinaryOperator::ArcTan2:
return F("atan2");
case BinaryOperator::ArcTan2_d:
return F("atan2_d");
case BinaryOperator::FMod:
return F("fmod");
}
return F("");
}
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
RulesCalculate_t::RulesCalculate_t() {
for (int i = 0; i < STACK_SIZE; ++i) {
@@ -18,9 +88,7 @@ RulesCalculate_t::RulesCalculate_t() {
/********************************************************************************************\
Calculate function for simple expressions
\*********************************************************************************************/
bool isError(CalculateReturnCode returnCode) {
return returnCode != CalculateReturnCode::OK;
}
bool isError(CalculateReturnCode returnCode) { return returnCode != CalculateReturnCode::OK; }
bool RulesCalculate_t::is_number(char oc, char c, char pc)
{
@@ -29,57 +97,59 @@ bool RulesCalculate_t::is_number(char oc, char c, char pc)
(c == '.') || // A decimal point of a floating point number.
((oc == '0') && ((c == 'x') || (c == 'b'))) || // HEX (0x) or BIN (0b) prefixes.
isxdigit(c) || // HEX digit also includes normal decimal numbers
((is_operator(oc) || ('\0' == oc)) && (c == '-')
&& (isdigit(pc) || ('\0' == pc))) // Beginning of a negative number after an operator or 'separator' and before a digit or end-of-digit.
((is_operator(oc) || ('\0' == oc)) && (c == '-')
&& (isdigit(pc) || ('\0' == pc))) // Beginning of a negative number after an operator or 'separator' and before a digit or
// end-of-digit.
;
}
bool RulesCalculate_t::is_operator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%';
}
bool RulesCalculate_t::is_operator(char c) { return c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%'; }
bool RulesCalculate_t::is_unary_operator(char c)
{
const UnaryOperator op = static_cast<UnaryOperator>(c);
return (op == UnaryOperator::Not || (
c >= static_cast<char>(UnaryOperator::Log) &&
c <= static_cast<char>(UnaryOperator::ArcTan_d)));
/*
switch (op) {
case UnaryOperator::Not:
case UnaryOperator::Log:
case UnaryOperator::Ln:
case UnaryOperator::Abs:
case UnaryOperator::Exp:
case UnaryOperator::Sqrt:
case UnaryOperator::Sq:
case UnaryOperator::Round:
case UnaryOperator::Sin:
case UnaryOperator::Cos:
case UnaryOperator::Tan:
case UnaryOperator::ArcSin:
case UnaryOperator::ArcCos:
case UnaryOperator::ArcTan:
case UnaryOperator::Sin_d:
case UnaryOperator::Cos_d:
case UnaryOperator::Tan_d:
case UnaryOperator::ArcSin_d:
case UnaryOperator::ArcCos_d:
case UnaryOperator::ArcTan_d:
return true;
}
return false;
*/
return op == UnaryOperator::Not || (
c >= static_cast<char>(UnaryOperator::Log) &&
c <= static_cast<char>(UnaryOperator::ArcTan_d));
/*
switch (op) {
case UnaryOperator::Not:
case UnaryOperator::Log:
case UnaryOperator::Ln:
case UnaryOperator::Abs:
case UnaryOperator::Exp:
case UnaryOperator::Sqrt:
case UnaryOperator::Sq:
case UnaryOperator::Round:
case UnaryOperator::Sin:
case UnaryOperator::Cos:
case UnaryOperator::Tan:
case UnaryOperator::ArcSin:
case UnaryOperator::ArcCos:
case UnaryOperator::ArcTan:
case UnaryOperator::Sin_d:
case UnaryOperator::Cos_d:
case UnaryOperator::Tan_d:
case UnaryOperator::ArcSin_d:
case UnaryOperator::ArcCos_d:
case UnaryOperator::ArcTan_d:
return true;
}
return false;
*/
}
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
// binary = 2-argument functions
bool RulesCalculate_t::is_binary_operator(char c)
{
return (c >= static_cast<char>(BinaryOperator::ArcTan2) &&
c <= static_cast<char>(BinaryOperator::FMod));
return c >= static_cast<char>(BinaryOperator::ArcTan2) &&
c <= static_cast<char>(BinaryOperator::FMod);
}
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
// quinary = 5-argument functions
@@ -127,13 +197,13 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_operator(char op, ESPEASY_RULES
return static_cast<int>(round(first)) % static_cast<int>(round(second));
#else
return static_cast<int>(roundf(first)) % static_cast<int>(roundf(second));
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case '^':
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return pow(first, second);
#else
return powf(first, second);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
default:
return 0;
}
@@ -144,43 +214,44 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
ESPEASY_RULES_FLOAT_TYPE ret{};
const UnaryOperator un_op = static_cast<UnaryOperator>(op);
switch (un_op) {
switch (un_op)
{
case UnaryOperator::Not:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return essentiallyZero(round(first)) ? 1 : 0;
#else
return essentiallyZero(roundf(first)) ? 1 : 0;
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Log:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return log10(first);
#else
return log10f(first);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Ln:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return log(first);
#else
return logf(first);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Abs:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return fabs(first);
#else
return fabsf(first);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Exp:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return exp(first);
#else
return expf(first);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Sqrt:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return sqrt(first);
#else
return sqrtf(first);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Sq:
return first * first;
case UnaryOperator::Round:
@@ -188,7 +259,7 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
return round(first);
#else
return roundf(first);
#endif
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
default:
break;
}
@@ -197,30 +268,31 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
const bool useDegree = angleDegree(un_op);
// First the trigonometric functions with angle as output
switch (un_op) {
switch (un_op)
{
case UnaryOperator::ArcSin:
case UnaryOperator::ArcSin_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
ret = asin(first);
#else
# else
ret = asinf(first);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return useDegree ? degrees(ret) : ret;
case UnaryOperator::ArcCos:
case UnaryOperator::ArcCos_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
ret = acos(first);
#else
# else
ret = acosf(first);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return useDegree ? degrees(ret) : ret;
case UnaryOperator::ArcTan:
case UnaryOperator::ArcTan_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
ret = atan(first);
#else
# else
ret = atanf(first);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return useDegree ? degrees(ret) : ret;
default:
break;
@@ -231,34 +303,36 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
first = radians(first);
}
switch (un_op) {
switch (un_op)
{
case UnaryOperator::Sin:
case UnaryOperator::Sin_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return sin(first);
#else
# else
return sinf(first);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Cos:
case UnaryOperator::Cos_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return cos(first);
#else
# else
return cosf(first);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
case UnaryOperator::Tan:
case UnaryOperator::Tan_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return tan(first);
#else
# else
return tanf(first);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
default:
break;
}
#else // if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
switch (un_op) {
switch (un_op)
{
case UnaryOperator::Sin:
case UnaryOperator::Sin_d:
case UnaryOperator::Cos:
@@ -281,33 +355,37 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
}
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_binary_operator(char op, ESPEASY_RULES_FLOAT_TYPE first, ESPEASY_RULES_FLOAT_TYPE second)
{
ESPEASY_RULES_FLOAT_TYPE ret{};
const BinaryOperator bin_op = static_cast<BinaryOperator>(op);
const BinaryOperator bin_op = static_cast<BinaryOperator>(op);
const bool useDegree = angleDegree(bin_op);
switch (bin_op) {
switch (bin_op)
{
case BinaryOperator::ArcTan2:
case BinaryOperator::ArcTan2_d:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
ret = atan2(first, second);
#else
# else
ret = atan2f(first, second);
#endif
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return useDegree ? degrees(ret) : ret;
case BinaryOperator::FMod:
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return fmod(first, second);
#else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
# else // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
return fmodf(first, second);
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
}
# endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
}
return ret;
}
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_quinary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_quinary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE first,
ESPEASY_RULES_FLOAT_TYPE second,
ESPEASY_RULES_FLOAT_TYPE third,
@@ -317,11 +395,11 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_quinary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE ret{};
const UnaryOperator qu_op = static_cast<UnaryOperator>(op);
if (UnaryOperator::Map == qu_op || UnaryOperator::MapC == qu_op) {
if ((UnaryOperator::Map == qu_op) || (UnaryOperator::MapC == qu_op)) {
// Clamp the result if the operator is MapC
if (qu_op == UnaryOperator::MapC) {
first = constrain(first, min(second, third), max(second, third));;
first = constrain(first, min(second, third), max(second, third));
}
ret = mapADCtoFloat(first, second, third, fourth, fifth);
}
@@ -351,28 +429,31 @@ CalculateReturnCode RulesCalculate_t::RPNCalculate(char *token)
ESPEASY_RULES_FLOAT_TYPE first = pop();
ret = push(apply_operator(token[0], first, second));
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate operator %c: 1: %.4f 2: %.4f"), token[0], first, second));
// FIXME TD-er: Regardless whether it is an error, all code paths return ret;
// if (isError(ret)) { return ret; }
// FIXME TD-er: Regardless whether it is an error, all code paths return ret;
// if (isError(ret)) { return ret; }
} else if (is_unary_operator(token[0]) && (token[1] == 0))
{
ESPEASY_RULES_FLOAT_TYPE first = pop();
ret = push(apply_unary_operator(token[0], first));
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate unary %d: 1: %.4f"), token[0], first));
// FIXME TD-er: Regardless whether it is an error, all code paths return ret;
// if (isError(ret)) { return ret; }
// FIXME TD-er: Regardless whether it is an error, all code paths return ret;
// if (isError(ret)) { return ret; }
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
} else if (is_binary_operator(token[0]) && (token[1] == 0))
{
const ESPEASY_RULES_FLOAT_TYPE second = pop();
const ESPEASY_RULES_FLOAT_TYPE first = pop();
ret = push(apply_binary_operator(token[0], first, second));
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate binary %d: 1: %.4f 2: %.4f"), token[0], first, second));
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
} else if (is_quinary_operator(token[0]) && (token[1] == 0))
{
@@ -383,21 +464,24 @@ CalculateReturnCode RulesCalculate_t::RPNCalculate(char *token)
ESPEASY_RULES_FLOAT_TYPE first = pop();
ret = push(apply_quinary_operator(token[0], first, second, third, fourth, fifth));
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate quinary %d: 1: %.4f 2: %.4f 3: %.4f 4: %.4f 5: %.4f"), token[0], first, second, third, fourth, fifth));
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate quinary %d: 1: %.4f 2: %.4f 3: %.4f 4: %.4f 5: %.4f"), token[0], first, second,
// third, fourth, fifth));
} else {
// Fetch next if there is any
ESPEASY_RULES_FLOAT_TYPE value{};
if (validDoubleFromString(token, value)) {
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate push value: %.4f token: %s"), value, token));
// } else {
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate unknown token: %s"), token));
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate push value: %.4f token: %s"), value, token));
// } else {
// addLog(LOG_LEVEL_INFO, strformat(F("RPNCalculate unknown token: %s"), token));
}
ret = push(value); // If it is a value, push to the stack
// FIXME TD-er: Regardless whether it is an error, all code paths return ret;
// if (isError(ret)) { return ret; }
// FIXME TD-er: Regardless whether it is an error, all code paths return ret;
// if (isError(ret)) { return ret; }
}
return ret;
@@ -411,7 +495,15 @@ CalculateReturnCode RulesCalculate_t::RPNCalculate(char *token)
// 1 + - left to right
int RulesCalculate_t::op_preced(const char c)
{
if (is_unary_operator(c)) { return 4; // right to left
// All function tokens (unary, binary and quinary) must have the highest precedence,
// or a pending operator in front of a function call is applied before the function is evaluated.
if (is_unary_operator(c) ||
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
is_binary_operator(c) ||
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
is_quinary_operator(c))
{
return 4; // right to left
}
switch (c)
@@ -431,27 +523,28 @@ int RulesCalculate_t::op_preced(const char c)
bool RulesCalculate_t::op_left_assoc(const char c)
{
if (is_operator(c)) { return true; // left to right
if (is_operator(c)) { return true; // left to right
}
/*
// FIXME TD-er: Disabled the check as the return value is false anyway.
if (is_unary_operator(c)) { return false; // right to left
}
*/
/*
// FIXME TD-er: Disabled the check as the return value is false anyway.
if (is_unary_operator(c)) { return false; // right to left
}
*/
return false;
}
/* unused:
unsigned int RulesCalculate_t::op_arg_count(const char c)
{
if (is_unary_operator(c)) { return 1; }
unsigned int RulesCalculate_t::op_arg_count(const char c)
{
if (is_unary_operator(c)) { return 1; }
if (is_operator(c)) { return 2; }
if (is_operator(c)) { return 2; }
if (is_quinary_operator(c)) { return 5; }
return 0;
}
*/
if (is_quinary_operator(c)) { return 5; }
return 0;
}
*/
CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RULES_FLOAT_TYPE *result)
{
@@ -492,15 +585,19 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
{
// Get peek-ahead char
pcpos = strpos + 1;
pc = *pcpos;
pc = *pcpos;
while ((pcpos < strend) && (' ' == pc)) {
++pcpos;
pc = *pcpos;
}
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate is_number: oc: %d c: %d/%c pc: %d token: %s input: %s sl: %u"), oc, c, c, pc, token, input, sl));
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate is_number: oc: %d c: %d/%c pc: %d token: %s input: %s sl: %u"), oc, c, c, pc,
// token, input, sl));
if ((pcpos >= strend)) {
pc = '\0';
}
// If the token is a number (identifier), then add it to the token queue.
if (is_number(oc, c, pc))
{
@@ -564,7 +661,22 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
*(TokenPos) = 0; // Mark end of token string
error = RPNCalculate(token);
TokenPos = token;
c = 0; // reset
if (isError(error)) { return error; }
// Finish the previous argument: pop all operators off the stack onto the token queue
// until the left parenthesis of the function call (which stays on the stack).
while (sl > 0 && stack[sl - 1] != '(')
{
*TokenPos = stack[sl - 1];
++TokenPos;
*(TokenPos) = 0; // Mark end of token string
error = RPNCalculate(token);
TokenPos = token;
if (isError(error)) { return error; }
sl--;
}
c = 0; // reset
}
// If the token is a left parenthesis, then push it onto the stack.
@@ -581,13 +693,16 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
{
bool pe = false;
sc = '\0';
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate stack content 0x%s"), formatToHex_array(reinterpret_cast<const uint8_t*>(stack), sl + 1).c_str()));
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate stack content 0x%s"), formatToHex_array(reinterpret_cast<const uint8_t*>(stack),
// sl + 1).c_str()));
// Until the token at the top of the stack is a left parenthesis,
// pop operators off the stack onto the token queue
while (sl < OPERATOR_STACK_SIZE)
{
*(TokenPos) = 0; // Mark end of token string
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate popping stack sl: %u token: %s sc: %d"), sl, token, sc));
if (sc == '(') {
// const auto first = pop(); // Get last value from stack
@@ -595,6 +710,7 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate at ( last value: %.4f sl: %u"), first, sl));
} else {
error = RPNCalculate(token);
// const auto first = pop(); // Get last value from stack
// push(first); // push back
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate last value on stack: %.4f sl: %u"), first, sl));
@@ -607,6 +723,7 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
if (sl > 0) {
sc = stack[sl - 1];
}
if (pe || (sl == 0)) {
break;
}
@@ -614,8 +731,10 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
if (sc == '(')
{
pe = true;
if (sl > 1) {
sc = stack[sl - 2];
if (is_operator(sc)) { // Not a function call
// Don't touch
} else if (is_unary_operator(sc) ||
@@ -625,9 +744,9 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
is_quinary_operator(sc)) { // Function call, so process the function too
*TokenPos = sc;
++TokenPos;
stack[sl - 2] = '\0'; // Don't process again on stack wind-down
stack[sl - 2] = '\0'; // Don't process again on stack wind-down
} else {
sc = '\0'; // Reset
sc = '\0'; // Reset
}
}
}
@@ -635,9 +754,11 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
{
*TokenPos = sc;
++TokenPos;
if (sl > 0) {
sl--;
}
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate next token: %s sl: %u sc: %d"), token, sl, sc));
}
}
@@ -652,6 +773,12 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
sl--;
}
// Also remove the function token that has just been processed (marked '\0' above),
// otherwise it blocks the operators below it and operator precedence is lost.
if ((sl > 0) && (stack[sl - 1] == '\0')) {
sl--;
}
// If the token at the top of the stack is a function token, pop it onto the token queue.
// FIXME TD-er: This sc value is never used, it is re-assigned a new value before it is being checked.
// if ((sl > 0) && (sl < OPERATOR_STACK_SIZE)) {
@@ -665,7 +792,8 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
++strpos;
}
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate final stack content 0x%s"), formatToHex_array(reinterpret_cast<const uint8_t*>(stack), sl + 1).c_str()));
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate final stack content 0x%s"), formatToHex_array(reinterpret_cast<const uint8_t*>(stack),
// sl + 1).c_str()));
// When there are no more tokens to read:
// While there are still operator tokens in the stack:
while (sl > 0)
@@ -678,8 +806,9 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
*(TokenPos) = 0; // Mark end of token string
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate closing up stack sl: %u token: %s sc: %d"), sl, token, sc));
error = RPNCalculate(token);
TokenPos = token;
error = RPNCalculate(token);
TokenPos = token;
// const auto first = pop(); // Get last value from stack
// push(first); // push back
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate closing, last value on stack: %.4f sl: %u"), first, sl));
@@ -693,6 +822,7 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
*(TokenPos) = 0; // Mark end of token string
error = RPNCalculate(token);
TokenPos = token;
// const auto first = pop(); // Get last value from stack
// push(first); // push back
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate final value on stack: %.4f sl: %u"), first, sl));
@@ -721,6 +851,7 @@ void preProcessReplace(String& input, UnaryOperator op) {
}
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
void preProcessReplace(String& input, BinaryOperator op) {
String find = toString(op);
@@ -731,11 +862,13 @@ void preProcessReplace(String& input, BinaryOperator op) {
input.replace(find, replace);
}
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
bool angleDegree(UnaryOperator op)
{
switch (op) {
switch (op)
{
case UnaryOperator::Sin_d:
case UnaryOperator::Cos_d:
case UnaryOperator::Tan_d:
@@ -750,9 +883,11 @@ bool angleDegree(UnaryOperator op)
}
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
bool angleDegree(BinaryOperator op)
{
return BinaryOperator::ArcTan2_d == op;
// switch (op) // Future extension for 4 or more BinaryOperator options and multiple _d options
// {
// case BinaryOperator::ArcTan2_d:
@@ -763,72 +898,7 @@ bool angleDegree(BinaryOperator op)
// }
// return false;
}
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
const __FlashStringHelper* toString(UnaryOperator op)
{
switch (op) {
case UnaryOperator::Not:
break; // No need to replace
case UnaryOperator::Log:
return F("log");
case UnaryOperator::Ln:
return F("ln");
case UnaryOperator::Abs:
return F("abs");
case UnaryOperator::Exp:
return F("exp");
case UnaryOperator::Sqrt:
return F("sqrt");
case UnaryOperator::Sq:
return F("sq");
case UnaryOperator::Round:
return F("round");
case UnaryOperator::Sin:
return F("sin");
case UnaryOperator::Sin_d:
return F("sin_d");
case UnaryOperator::Cos:
return F("cos");
case UnaryOperator::Cos_d:
return F("cos_d");
case UnaryOperator::Tan:
return F("tan");
case UnaryOperator::Tan_d:
return F("tan_d");
case UnaryOperator::ArcSin:
return F("asin");
case UnaryOperator::ArcSin_d:
return F("asin_d");
case UnaryOperator::ArcCos:
return F("acos");
case UnaryOperator::ArcCos_d:
return F("acos_d");
case UnaryOperator::ArcTan:
return F("atan");
case UnaryOperator::ArcTan_d:
return F("atan_d");
case UnaryOperator::Map:
return F("map");
case UnaryOperator::MapC:
return F("mapc");
}
return F("");
}
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
const __FlashStringHelper* toString(BinaryOperator op)
{
switch (op) {
case BinaryOperator::ArcTan2:
return F("atan2");
case BinaryOperator::ArcTan2_d:
return F("atan2_d");
case BinaryOperator::FMod:
return F("fmod");
}
return F("");
}
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
String RulesCalculate_t::preProces(const String& input)
@@ -837,33 +907,33 @@ String RulesCalculate_t::preProces(const String& input)
const UnaryOperator operators[] = {
UnaryOperator::Not
,UnaryOperator::Log
,UnaryOperator::Ln
,UnaryOperator::Abs
,UnaryOperator::Exp
,UnaryOperator::Sqrt
,UnaryOperator::Sq
,UnaryOperator::Round
, UnaryOperator::Log
, UnaryOperator::Ln
, UnaryOperator::Abs
, UnaryOperator::Exp
, UnaryOperator::Sqrt
, UnaryOperator::Sq
, UnaryOperator::Round
#if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
// Try the "arc" functions first or else "sin" is already replaced when "asin" is tried.
,UnaryOperator::ArcSin
,UnaryOperator::ArcSin_d
,UnaryOperator::Sin
,UnaryOperator::Sin_d
, UnaryOperator::ArcSin
, UnaryOperator::ArcSin_d
, UnaryOperator::Sin
, UnaryOperator::Sin_d
,UnaryOperator::ArcCos
,UnaryOperator::ArcCos_d
,UnaryOperator::Cos
,UnaryOperator::Cos_d
, UnaryOperator::ArcCos
, UnaryOperator::ArcCos_d
, UnaryOperator::Cos
, UnaryOperator::Cos_d
,UnaryOperator::ArcTan
,UnaryOperator::ArcTan_d
,UnaryOperator::Tan
,UnaryOperator::Tan_d
, UnaryOperator::ArcTan
, UnaryOperator::ArcTan_d
, UnaryOperator::Tan
, UnaryOperator::Tan_d
#endif // if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
,UnaryOperator::Map // FIXME ?Move to new QuintaryOperator enum?
,UnaryOperator::MapC
, UnaryOperator::Map // FIXME ?Move to new QuintaryOperator enum?
, UnaryOperator::MapC
};
@@ -872,11 +942,20 @@ String RulesCalculate_t::preProces(const String& input)
for (size_t i = 0; i < nrOperators; ++i) {
const UnaryOperator op = operators[i];
#if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
if (op == UnaryOperator::ArcSin && preprocessed.indexOf(F("sin")) == -1) i += 3;
else if (op == UnaryOperator::ArcCos && preprocessed.indexOf(F("cos")) == -1) i += 3;
else if (op == UnaryOperator::ArcTan && preprocessed.indexOf(F("tan")) == -1) i += 3;
else
#endif
if ((op == UnaryOperator::ArcSin) &&
(preprocessed.indexOf(F("sin")) == -1)) { i += 3;
}
else if ((op == UnaryOperator::ArcCos) &&
(preprocessed.indexOf(F("cos")) ==
-1)) { i += 3;
}
else if ((op == UnaryOperator::ArcTan) &&
(preprocessed.indexOf(F("tan")) ==
-1)) { i += 3;
}
else
#endif // if FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
{
preProcessReplace(preprocessed, op);
}
@@ -891,6 +970,7 @@ String RulesCalculate_t::preProces(const String& input)
};
constexpr size_t nrOperators2 = NR_ELEMENTS(operators2);
for (size_t i = 0; i < nrOperators2; ++i) {
const BinaryOperator op = operators2[i];
preProcessReplace(preprocessed, op);
@@ -899,4 +979,3 @@ String RulesCalculate_t::preProces(const String& input)
return preprocessed;
}
+59 -57
View File
@@ -11,19 +11,20 @@
#define TOKEN_MAX 20
#if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
#define TOKEN_LENGTH 40
# define TOKEN_LENGTH 40
#else
#define TOKEN_LENGTH 25
#endif
# define TOKEN_LENGTH 25
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
#define OPERATOR_STACK_SIZE 32
enum class CalculateReturnCode : uint8_t{
enum class CalculateReturnCode : uint8_t {
OK = 0u,
ERROR_STACK_OVERFLOW = 1u,
ERROR_BAD_OPERATOR = 2u,
ERROR_PARENTHESES_MISMATCHED = 3u,
ERROR_UNKNOWN_TOKEN = 4u,
ERROR_TOKEN_LENGTH_EXCEEDED = 5u
};
bool isError(CalculateReturnCode returnCode);
@@ -36,80 +37,82 @@ bool isError(CalculateReturnCode returnCode);
enum class UnaryOperator : uint8_t {
Not = '!',
Log = 192u, // Start at some ASCII code we don't expect in the rules.
Ln, // Natural logarithm
Abs, // Absolute value
Exp, // exponential value, e^x
Sqrt, // Square Root
Sq, // Square, x^2
Round, // Rounds to the nearest integer, but rounds halfway cases away from zero (instead of to the nearest even integer).
Sin, // Sine (radian)
Sin_d, // Sine (degree)
Cos, // Cosine (radian)
Cos_d, // Cosine (degree)
Tan, // Tangent (radian)
Tan_d, // Tangent (degree)
ArcSin, // Arc Sine (radian)
ArcSin_d, // Arc Sine (degree)
ArcCos, // Arc Cosine (radian)
ArcCos_d, // Arc Cosine (degree)
ArcTan, // Arc Tangent (radian)
ArcTan_d, // Arc Tangent (degree)
Map, // Map (value, lowFrom, highFrom, lowTo, highTo) (not really unary...)
MapC, // Map (value, lowFrom, highFrom, lowTo, highTo) and clamp to lowTo/highTo
Ln, // Natural logarithm
Abs, // Absolute value
Exp, // exponential value, e^x
Sqrt, // Square Root
Sq, // Square, x^2
Round, // Rounds to the nearest integer, but rounds halfway cases away from zero (instead of to the nearest even integer).
Sin, // Sine (radian)
Sin_d, // Sine (degree)
Cos, // Cosine (radian)
Cos_d, // Cosine (degree)
Tan, // Tangent (radian)
Tan_d, // Tangent (degree)
ArcSin, // Arc Sine (radian)
ArcSin_d, // Arc Sine (degree)
ArcCos, // Arc Cosine (radian)
ArcCos_d, // Arc Cosine (degree)
ArcTan, // Arc Tangent (radian)
ArcTan_d, // Arc Tangent (degree)
Map, // Map (value, lowFrom, highFrom, lowTo, highTo) (not really unary...)
MapC, // Map (value, lowFrom, highFrom, lowTo, highTo) and clamp to lowTo/highTo
};
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
enum class BinaryOperator : uint8_t {
ArcTan2 = 220u, // Arc Tangent 2 (radian)
ArcTan2_d, // Arc Tangent 2 (degrees)
FMod, // Float-modulo
ArcTan2 = 220u, // Arc Tangent 2 (radian)
ArcTan2_d, // Arc Tangent 2 (degrees)
FMod, // Float-modulo
};
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
void preProcessReplace(String & input,
UnaryOperator op);
bool angleDegree(UnaryOperator op);
const __FlashStringHelper* toString(UnaryOperator op);
void preProcessReplace(String & input,
UnaryOperator op);
bool angleDegree(UnaryOperator op);
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
bool angleDegree(BinaryOperator op);
const __FlashStringHelper* toString(BinaryOperator op);
bool angleDegree(BinaryOperator op);
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
class RulesCalculate_t {
class RulesCalculate_t
{
private:
ESPEASY_RULES_FLOAT_TYPE globalstack[STACK_SIZE]{};
ESPEASY_RULES_FLOAT_TYPE *sp = globalstack - 1;
ESPEASY_RULES_FLOAT_TYPE *sp = globalstack - 1;
const ESPEASY_RULES_FLOAT_TYPE *sp_max = &globalstack[STACK_SIZE - 1];
// Check if it matches part of a number (identifier)
// @param oc Previous character
// @param c Current character
bool is_number(char oc,
char c,
char pc);
static bool is_number(char oc,
char c,
char pc);
bool is_operator(char c);
static bool is_operator(char c);
bool is_unary_operator(char c);
static bool is_unary_operator(char c);
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
bool is_binary_operator(char c);
static bool is_binary_operator(char c);
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
bool is_quinary_operator(char c);
static bool is_quinary_operator(char c);
CalculateReturnCode push(ESPEASY_RULES_FLOAT_TYPE value);
CalculateReturnCode push(ESPEASY_RULES_FLOAT_TYPE value);
ESPEASY_RULES_FLOAT_TYPE pop();
ESPEASY_RULES_FLOAT_TYPE pop();
ESPEASY_RULES_FLOAT_TYPE apply_operator(char op,
ESPEASY_RULES_FLOAT_TYPE first,
ESPEASY_RULES_FLOAT_TYPE second);
ESPEASY_RULES_FLOAT_TYPE apply_operator(char op,
ESPEASY_RULES_FLOAT_TYPE first,
ESPEASY_RULES_FLOAT_TYPE second);
ESPEASY_RULES_FLOAT_TYPE apply_unary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE first);
ESPEASY_RULES_FLOAT_TYPE apply_unary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE first);
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
ESPEASY_RULES_FLOAT_TYPE apply_binary_operator(char op,
@@ -117,7 +120,7 @@ private:
ESPEASY_RULES_FLOAT_TYPE second);
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
ESPEASY_RULES_FLOAT_TYPE apply_quinary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE apply_quinary_operator(char op,
ESPEASY_RULES_FLOAT_TYPE first,
ESPEASY_RULES_FLOAT_TYPE second,
ESPEASY_RULES_FLOAT_TYPE third,
@@ -134,9 +137,9 @@ private:
// 3 ^ left to right
// 2 * / % left to right
// 1 + - left to right
int op_preced(const char c);
static int op_preced(const char c);
bool op_left_assoc(const char c);
static bool op_left_assoc(const char c);
// unused: unsigned int op_arg_count(const char c);
@@ -144,14 +147,13 @@ public:
RulesCalculate_t();
CalculateReturnCode doCalculate(const char *input,
ESPEASY_RULES_FLOAT_TYPE *result);
CalculateReturnCode doCalculate(const char *input,
ESPEASY_RULES_FLOAT_TYPE *result);
// Try to replace multi byte operators with single character ones.
// For example log, sin, cos, tan.
static String preProces(const String& input);
};
}; // class RulesCalculate_t
#endif // ifndef HELPERS_RULES_CALCULATE_H
File diff suppressed because it is too large. Load diff
+210 -222
View File
@@ -22,159 +22,198 @@ unsigned int count_newlines(const String& str);
Concatenate using code which results in the smallest compiled code
\*********************************************************************************************/
String concat(const __FlashStringHelper * str, const String &val);
String concat(const __FlashStringHelper * str, const __FlashStringHelper *val);
String concat(const __FlashStringHelper *str,
const String & val);
String concat(const __FlashStringHelper *str,
const __FlashStringHelper *val);
String concat(const __FlashStringHelper * str, const char* val);
String concat(const __FlashStringHelper * str, int val);
String concat(const __FlashStringHelper * str, const char& c);
String concat(const __FlashStringHelper *str,
const char *val);
String concat(const __FlashStringHelper *str,
int val);
String concat(const __FlashStringHelper *str,
const char & c);
#if defined(ESP32) && !defined(__riscv)
String concat(const __FlashStringHelper * str, const int32_t& val);
#endif
String concat(const __FlashStringHelper * str, const float& val);
String concat(const __FlashStringHelper * str, const double& val);
String concat(const __FlashStringHelper * str, const uint32_t& val);
String concat(const __FlashStringHelper *str,
const int32_t & val);
#endif // if defined(ESP32) && !defined(__riscv)
String concat(const __FlashStringHelper *str,
const float & val);
String concat(const __FlashStringHelper *str,
const double & val);
String concat(const __FlashStringHelper *str,
const uint32_t & val);
#if defined(ESP32) && !defined(__riscv)
String concat(const __FlashStringHelper * str, const size_t& val);
#endif
String concat(const char& c, const __FlashStringHelper *val);
String concat(int i, const __FlashStringHelper *val);
String concat(uint32_t i, const __FlashStringHelper *val);
String concat(const String & str, const __FlashStringHelper *val);
String concat(const String & str, const String & val);
String concat(const String & str, const char* val);
String concat(const String & val, const char& c);
String concat(String &&val, const char& c);
String concat(String &&str, const __FlashStringHelper * val);
String concat(const __FlashStringHelper *str, String && val);
String concat(const __FlashStringHelper *str,
const size_t & val);
#endif // if defined(ESP32) && !defined(__riscv)
String concat(const char & c,
const __FlashStringHelper *val);
String concat(int i,
const __FlashStringHelper *val);
String concat(uint32_t i,
const __FlashStringHelper *val);
String concat(const String & str,
const __FlashStringHelper *val);
String concat(const String& str,
const String& val);
String concat(const String& str,
const char *val);
String concat(const String& val,
const char & c);
String concat(String && val,
const char& c);
String concat(String && str,
const __FlashStringHelper *val);
String concat(const __FlashStringHelper *str,
String && val);
String concat(const char& str, const String &val);
String concat(const char & str,
const String& val);
/*
template <typename T>
String concat(const __FlashStringHelper * str, const T &val) {
# ifdef USE_SECOND_HEAP
HeapSelectDram ephemeral;
# endif // ifdef USE_SECOND_HEAP
template <typename T>
String concat(const __FlashStringHelper * str, const T &val) {
# ifdef USE_SECOND_HEAP
HeapSelectDram ephemeral;
# endif // ifdef USE_SECOND_HEAP
String res(str);
res.concat(val);
return res;
}
*/
String res(str);
res.concat(val);
return res;
}
*/
/*
template <typename T>
String concat(const String& str, const T &val) {
# ifdef USE_SECOND_HEAP
HeapSelectDram ephemeral;
# endif // ifdef USE_SECOND_HEAP
template <typename T>
String concat(const String& str, const T &val) {
# ifdef USE_SECOND_HEAP
HeapSelectDram ephemeral;
# endif // ifdef USE_SECOND_HEAP
String res(str);
res.concat(val);
return res;
}
*/
String res(str);
res.concat(val);
return res;
}
*/
bool remove(String& str, const String& toRemove);
bool remove(String& str, const __FlashStringHelper * toRemove);
bool remove(String& str, const char& toRemove);
bool remove(String & str,
const String& toRemove);
bool remove(String & str,
const __FlashStringHelper *toRemove);
bool remove(String & str,
const char& toRemove);
bool removeSpace(String& str);
bool equals(const String& str, const __FlashStringHelper * f_str);
bool equals(const String& str, const char& c);
bool equals(const String & str,
const __FlashStringHelper *f_str);
bool equals(const String& str,
const char & c);
// Move the string to 2nd heap if present
void move_special(String& dest, String&& source);
void move_special(String & dest,
String&& source);
String move_special(String&& source);
void move_special(String& dest, String&& source, size_t strLengthThreshold);
String move_special(String&& source, size_t strLengthThreshold);
void move_special(String & dest,
String&& source,
size_t strLengthThreshold);
String move_special(String&& source,
size_t strLengthThreshold);
// Try to reserve on the heap with the most space available
bool reserve_special(String& str, size_t size);
bool reserve_special(String& str, size_t size, size_t strLengthThreshold);
bool reserve_special(String& str,
size_t size);
bool reserve_special(String& str,
size_t size,
size_t strLengthThreshold);
// Arduino String does not have a function to de-allocate its internal buffer
// This is a special trick to de-allocate its internal buffer and thus free up memory.
void free_string(String& str);
/*
template <typename T>
bool equals(const String& str, const T &val) {
return str.equals(String(val));
}
*/
template <typename T>
bool equals(const String& str, const T &val) {
return str.equals(String(val));
}
*/
/********************************************************************************************\
Format string using vsnprintf
See: https://cplusplus.com/reference/cstdio/printf/
\*********************************************************************************************/
String strformat(const String& format, ...);
String strformat(const __FlashStringHelper * format, ...);
String strformat(const String& format,
...);
String strformat(const __FlashStringHelper *format,
...);
/********************************************************************************************\
Convert a char string to IP uint8_t array
\*********************************************************************************************/
bool isIP(const String& string);
bool isIP(const String& string);
bool str2ip(const String& string,
uint8_t *IP);
bool str2ip(const String& string,
uint8_t *IP);
bool str2ip(const char *string,
uint8_t *IP);
bool str2ip(const char *string,
uint8_t *IP);
String formatIP(const IPAddress& ip, bool includeZone = false);
String formatIP(const IPAddress& ip,
bool includeZone = false);
const __FlashStringHelper * boolToString(bool value);
const __FlashStringHelper* boolToString(bool value);
/*********************************************************************************************\
Typical string replace functions.
\*********************************************************************************************/
void removeExtraNewLine(String& line);
void removeExtraNewLine(String& line);
// Remove all occurences of given character from the string
void removeChar(String& line, char character);
void removeChar(String& line,
char character);
void addNewLine(String& line);
void addNewLine(String& line);
size_t UTF8_charLength(uint8_t firstByte);
void replaceUnicodeByChar(String& line, char replChar);
void replaceUnicodeByChar(String& line,
char replChar);
// Pad string with given char to minimum length
void padToMinimumLength(String& line, uint32_t minimumLength, char padChar = ' ');
void padToMinimumLength(String & line,
uint32_t minimumLength,
char padChar = ' ');
// Prefix string with given char to minimum length
void prefixToMinimumLength(String& line, uint32_t minimumLength, char prefixChar = ' ');
void prefixToMinimumLength(String & line,
uint32_t minimumLength,
char prefixChar = ' ');
/*********************************************************************************************\
Format a value to the set number of decimals
\*********************************************************************************************/
String doFormatUserVar(struct EventStruct *event,
uint8_t rel_index,
uint8_t rel_index,
bool mustCheck,
bool & isvalid);
String formatUserVarNoCheck(taskIndex_t TaskIndex,
uint8_t rel_index);
uint8_t rel_index);
String formatUserVar(taskIndex_t TaskIndex,
uint8_t rel_index,
uint8_t rel_index,
bool & isvalid);
String formatUserVarNoCheck(struct EventStruct *event,
uint8_t rel_index);
uint8_t rel_index);
String formatUserVar(struct EventStruct *event,
uint8_t rel_index,
uint8_t rel_index,
bool & isvalid);
#if FEATURE_STRING_VARIABLES
@@ -190,9 +229,11 @@ String get_formatted_Controller_number(cpluginID_t cpluginID);
String get_formatted_Plugin_number(pluginID_t pluginID);
// Prepend zeroes till the string value length is nrDigits
String formatIntLeadingZeroes(int value, int nrDigits);
String formatIntLeadingZeroes(const String& value, int nrDigits);
// Prepend zeroes till the string value length is nrDigits
String formatIntLeadingZeroes(int value,
int nrDigits);
String formatIntLeadingZeroes(const String& value,
int nrDigits);
/*********************************************************************************************\
Wrap a string with given pre- and postfix string.
@@ -200,10 +241,11 @@ String formatIntLeadingZeroes(const String& value, int nrDigits);
String wrap_braces(const String& string);
String wrap_String(const String& string,
char wrap);
char wrap);
String wrap_String(const String& string,
char char1, char char2);
char char1,
char char2);
String wrapIfContains(const String& value,
char contains,
@@ -217,22 +259,18 @@ String wrapWithQuotesIfContainsParameterSeparatorChar(const String& text);
Format an object value pair for use in JSON.
\*********************************************************************************************/
String to_json_value(const String& value,
bool wrapInQuotes = false);
bool is_json_formatted(const String& value);
bool wrapInQuotes = false);
/*********************************************************************************************\
Strip wrapping chars (e.g. quotes)
\*********************************************************************************************/
String stripWrappingChar(const String& text,
char wrappingChar);
bool stringWrappedWithChar(const String& text,
char wrappingChar);
bool isQuoteChar(char c);
bool findUnusedQuoteChar(const String& text, char& quotechar) ;
bool findUnusedQuoteChar(const String& text,
char & quotechar);
bool isParameterSeparatorChar(char c);
@@ -242,13 +280,13 @@ bool isWrappedWithQuotes(const String& text);
String stripQuotes(const String& text);
bool safe_strncpy(char *dest,
const __FlashStringHelper * source,
size_t max_size);
bool safe_strncpy(char *dest,
const __FlashStringHelper *source,
size_t max_size);
bool safe_strncpy(char *dest,
const String& source,
size_t max_size);
bool safe_strncpy(char *dest,
const String& source,
size_t max_size);
bool safe_strncpy(char *dest,
const char *source,
@@ -263,19 +301,19 @@ String to_internal_string(const String& input,
IndexFind = 1 => command.
// FIXME TD-er: parseString* should use index starting at 0.
\*********************************************************************************************/
String parseString(const char * string,
uint8_t indexFind,
char separator = ',',
bool trimResult = true);
String parseString(const char *string,
uint8_t indexFind,
char separator = ',',
bool trimResult = true);
String parseString(const String& string,
uint8_t indexFind,
char separator = ',',
char separator = ',',
bool trimResult = true);
String parseStringKeepCase(const String& string,
uint8_t indexFind,
char separator = ',',
char separator = ',',
bool trimResult = true);
String parseStringKeepCaseNoTrim(const String& string,
@@ -284,32 +322,32 @@ String parseStringKeepCaseNoTrim(const String& string,
String parseStringToEnd(const String& string,
uint8_t indexFind,
char separator = ',',
char separator = ',',
bool trimResult = true);
String parseStringToEndKeepCase(const String& string,
uint8_t indexFind,
char separator = ',',
char separator = ',',
bool trimResult = true);
String parseStringToEndKeepCaseNoTrim(const String& string,
uint8_t indexFind,
char separator = ',');
String tolerantParseStringKeepCase(const char * string,
uint8_t indexFind,
char separator = ',',
bool trimResult = true);
String tolerantParseStringKeepCase(const char *string,
uint8_t indexFind,
char separator = ',',
bool trimResult = true);
String tolerantParseStringKeepCase(const String& string,
uint8_t indexFind,
char separator = ',',
char separator = ',',
bool trimResult = true);
String parseHexTextString(const String& argument,
int index = 2);
std::vector<uint8_t> parseHexTextData(const String& argument,
int index = 2);
String parseHexTextString(const String& argument,
int index = 2);
std::vector<uint8_t>parseHexTextData(const String& argument,
int index = 2);
/*********************************************************************************************\
@@ -318,7 +356,10 @@ std::vector<uint8_t> parseHexTextData(const String& argument,
Code (c) Tasmota:
https://github.com/arendst/Tasmota/blob/293ae8064d753e6d38488b46d21cdc52a4a6e637/tasmota/tasmota_support/support.ino#L937
\*********************************************************************************************/
char* GetTextIndexed(char* destination, size_t destination_size, uint32_t index, const char* haystack);
char* GetTextIndexed(char *destination,
size_t destination_size,
uint32_t index,
const char*haystack);
/*********************************************************************************************\
GetCommandCode: Find string in large PROGMEM stored string
@@ -326,10 +367,13 @@ char* GetTextIndexed(char* destination, size_t destination_size, uint32_t index,
Code (c) Tasmota:
https://github.com/arendst/Tasmota/blob/293ae8064d753e6d38488b46d21cdc52a4a6e637/tasmota/tasmota_support/support.ino#L967
\*********************************************************************************************/
int GetCommandCode(char* destination, size_t destination_size, const char* needle, const char* haystack);
int GetCommandCode(const char* needle, const char* haystack);
int GetCommandCode(char *destination,
size_t destination_size,
const char*needle,
const char*haystack);
int GetCommandCode(const char*needle,
const char*haystack);
// escapes special characters in strings for use in html-forms
@@ -345,55 +389,55 @@ void htmlStrongEscape(String& html);
String URLEncode(const String& msg);
bool repl(const __FlashStringHelper * key,
const String& val,
String & s,
bool useURLencode);
bool repl(const __FlashStringHelper *key,
const String & val,
String & s,
bool useURLencode);
bool repl(const __FlashStringHelper * key,
const char* val,
String & s,
bool useURLencode);
bool repl(const __FlashStringHelper *key,
const char *val,
String & s,
bool useURLencode);
bool repl(const __FlashStringHelper * key1,
const __FlashStringHelper * key2,
const char* val,
String & s,
bool useURLencode);
bool repl(const __FlashStringHelper *key1,
const __FlashStringHelper *key2,
const char *val,
String & s,
bool useURLencode);
bool repl(const String& key,
const String& val,
String & s,
bool useURLencode);
bool repl(const String& key,
const String& val,
String & s,
bool useURLencode);
void parseSpecialCharacters(String& s,
bool useURLencode);
bool useURLencode);
/********************************************************************************************\
replace other system variables like %sysname%, %systime%, %ip%
\*********************************************************************************************/
void parseControllerVariables(String & s,
struct EventStruct *event,
bool useURLencode);
bool useURLencode);
void parseSingleControllerVariable(String & s,
struct EventStruct* event,
uint8_t taskValueIndex,
bool useURLencode);
void parseSingleControllerVariable(String & s,
struct EventStruct*event,
uint8_t taskValueIndex,
bool useURLencode);
#if FEATURE_MQTT_DISCOVER
void parseDeviceClassVariable(String & s,
const __FlashStringHelper* devclass,
bool useURLencode);
void parseDeviceClassVariable(String & s,
const __FlashStringHelper*devclass,
bool useURLencode);
void parseUniqueIdVariable(String & s,
const String& uniqueId,
bool useURLencode);
void parseElementIdVariable(String & s,
const String& elementId,
bool useURLencode);
#endif
void parseElementIdVariable(String & s,
const String& elementId,
bool useURLencode);
#endif // if FEATURE_MQTT_DISCOVER
#if FEATURE_STRING_VARIABLES
void parseValNameVariable(String & s,
@@ -402,62 +446,18 @@ void parseValNameVariable(String & s,
#endif // if FEATURE_STRING_VARIABLES
void parseSystemVariables(String& s,
bool useURLencode);
bool useURLencode);
void parseEventVariables(String & s,
struct EventStruct *event,
bool useURLencode);
bool useURLencode);
bool getConvertArgument(const __FlashStringHelper * marker,
const String& s,
float & argument,
int & startIndex,
int & endIndex);
bool getConvertArgument2(const __FlashStringHelper * marker,
const String& s,
float & arg1,
float & arg2,
int & startIndex,
int & endIndex);
#if FEATURE_STRING_VARIABLES
bool getConvertArgumentStrFormat(const __FlashStringHelper *marker,
const String & s,
String & argStr,
float & arg1,
float & arg2,
int & startIndex,
int & endIndex);
#endif // if FEATURE_STRING_VARIABLES
bool getConvertArgumentStr(const __FlashStringHelper *marker,
const String & s,
String & argument,
int & startIndex,
int & endIndex);
bool getConvertArgumentString(const __FlashStringHelper * marker,
const String& s,
String & argumentString,
int & startIndex,
int & endIndex);
bool getConvertArgumentString(const String& marker,
const String& s,
String & argumentString,
int & startIndex,
int & endIndex);
// Parse conversions marked with "%conv_marker%(float)"
// Must be called last, since all sensor values must be converted, processed, etc.
void parseStandardConversions(String& s,
bool useURLencode);
bool useURLencode);
#if FEATURE_STRING_VARIABLES
String get_date_time_from_timestamp(time_t unix_timestamp, bool am_pm, bool iso_format);
String get_weekday_from_timestamp(time_t unix_timestamp);
#endif // if FEATURE_STRING_VARIABLES
bool HasArgv(const char *string,
unsigned int argc);
@@ -467,30 +467,18 @@ bool GetArgv(const char *string,
unsigned int argc,
char separator = ',');
bool GetArgv(const char *string,
const size_t & string_len,
String & argvString,
unsigned int argc,
unsigned int & string_pos,
unsigned int & argc_pos,
char separator = ',');
/*
bool GetArgvBeginEnd(const char *string,
const unsigned int argc,
int & pos_begin,
int & pos_end,
char separator = ',');
*/
bool GetArgvBeginEnd(const char *string,
const size_t & string_len,
const unsigned int argc,
int & pos_begin,
int & pos_end,
unsigned int & string_pos,
unsigned int & argc_pos,
char separator = ',');
bool GetArgv(const char *string,
const size_t& string_len,
String & argvString,
unsigned int argc,
unsigned int& string_pos,
unsigned int& argc_pos,
char separator = ',');
bool ContainsAny(const String& str, const char * charsToFind, size_t nrCharsToFind);
bool ContainsAny(const String& str, const String& charsToFind);
bool ContainsAny(const String& str,
const char *charsToFind,
size_t nrCharsToFind);
bool ContainsAny(const String& str,
const String& charsToFind);
#endif // HELPERS_STRINGCONVERTER_H
+15 -14
View File
@@ -353,6 +353,20 @@ String formatToHex_array(const uint8_t* data, size_t size)
return res;
}
static String formatULLtoHex_no_prefix(const uint64_t& value, unsigned int minimal_hex_digits)
{
const uint32_t msb_val = static_cast<uint32_t>(value >> 32);
const uint32_t lsb_val = static_cast<uint32_t>(value & 0xFFFFFFFF);
String res;
res.reserve(16);
res += formatToHex_no_prefix(msb_val, 8);
res += formatToHex_no_prefix(lsb_val, 8);
while (minimal_hex_digits < res.length() && res.startsWith(F("0"))) {
res = res.substring(1);
}
return res;
}
String formatULLtoHex(const uint64_t& value,
const __FlashStringHelper * prefix,
unsigned int minimal_hex_digits)
@@ -371,19 +385,6 @@ String formatULLtoHex(const uint64_t& value, unsigned int minimal_hex_digits)
return formatULLtoHex(value, F("0x"), minimal_hex_digits);
}
String formatULLtoHex_no_prefix(const uint64_t& value, unsigned int minimal_hex_digits)
{
const uint32_t msb_val = static_cast<uint32_t>(value >> 32);
const uint32_t lsb_val = static_cast<uint32_t>(value & 0xFFFFFFFF);
String res;
res.reserve(16);
res += formatToHex_no_prefix(msb_val, 8);
res += formatToHex_no_prefix(lsb_val, 8);
while (minimal_hex_digits < res.length() && res.startsWith(F("0"))) {
res = res.substring(1);
}
return res;
}
String formatULLtoHex_decimal(const uint64_t& value)
{
@@ -481,7 +482,7 @@ String formatToHex_decimal(uint32_t value, uint32_t factor) {
}
int intFromHexChar(char a)
static int intFromHexChar(char a)
{
if ((a >= 'A') && (a <= 'F')) { return a - 'A' + 10; }
else if ((a >= 'a') && (a <= 'f')) { return a - 'a' + 10; }
@@ -105,8 +105,6 @@ String formatULLtoHex(const uint64_t& value,
String formatULLtoHex(const uint64_t& value, unsigned int minimal_hex_digits = 0);
String formatULLtoHex_no_prefix(const uint64_t& value, unsigned int minimal_hex_digits = 0);
String formatULLtoHex_decimal(const uint64_t& value);
@@ -133,8 +131,6 @@ String formatToHex_decimal(uint32_t value);
String formatToHex_decimal(uint32_t value,
uint32_t factor);
int intFromHexChar(char a);
String stringFromHexArray(const String& arr);
#endif // ifndef HELPERS_STRINGCONVERTER_NUMERICAL_H
+13 -8
View File
@@ -57,22 +57,27 @@
# define KV_SETID(S)
#endif // ifndef LIMIT_BUILD_SIZE
KeyValueStruct make_kv(const __FlashStringHelper *key, int val)
static KeyValueStruct make_kv(const __FlashStringHelper *key, bool val)
{
return KeyValueStruct(key, val, KeyValueStruct::Format::Default);
}
KeyValueStruct make_kv(const __FlashStringHelper *key, uint32_t val)
static KeyValueStruct make_kv(const __FlashStringHelper *key, int val)
{
return KeyValueStruct(key, val, KeyValueStruct::Format::Default);
}
KeyValueStruct make_kv(const __FlashStringHelper *key, uint64_t val)
static KeyValueStruct make_kv(const __FlashStringHelper *key, uint32_t val)
{
return KeyValueStruct(key, val, KeyValueStruct::Format::Default);
}
KeyValueStruct make_kv(const __FlashStringHelper *key, const float & val,
static KeyValueStruct make_kv(const __FlashStringHelper *key, uint64_t val)
{
return KeyValueStruct(key, val, KeyValueStruct::Format::Default);
}
static KeyValueStruct make_kv(const __FlashStringHelper *key, const float & val,
uint8_t nrDecimals)
{
KeyValueStruct kv(key, KeyValueStruct::Format::Default);
@@ -80,22 +85,22 @@ KeyValueStruct make_kv(const __FlashStringHelper *key, const float & val,
return kv;
}
KeyValueStruct make_kv(const __FlashStringHelper *key, const __FlashStringHelper *val)
static KeyValueStruct make_kv(const __FlashStringHelper *key, const __FlashStringHelper *val)
{
return KeyValueStruct(key, val, KeyValueStruct::Format::Default);
}
KeyValueStruct make_kv(const __FlashStringHelper *key, String &&val)
static KeyValueStruct make_kv(const __FlashStringHelper *key, String &&val)
{
return KeyValueStruct(key, val, KeyValueStruct::Format::Default);
}
KeyValueStruct make_kv(const __FlashStringHelper *key, String &&val, KeyValueStruct::Format format)
static KeyValueStruct make_kv(const __FlashStringHelper *key, String &&val, KeyValueStruct::Format format)
{
return KeyValueStruct(key, val, format);
}
KeyValueStruct make_kv(const __FlashStringHelper *key, const IPAddress& val, bool includeZone = false)
static KeyValueStruct make_kv(const __FlashStringHelper *key, const IPAddress& val, bool includeZone = false)
{
ValueStruct v;
v.setIPAddress(val, includeZone);
+8 -8
View File
@@ -44,7 +44,7 @@
#if defined(ESP8266)
# include <ESP8266WiFi.h>
int WIFI_CONNECT_STATUS() {
static int WIFI_CONNECT_STATUS() {
if (WiFi.isConnected()) {
return 7;
}
@@ -53,7 +53,7 @@ int WIFI_CONNECT_STATUS() {
#endif // if defined(ESP8266)
#if defined(ESP32)
# include <WiFi.h>
int WIFI_CONNECT_STATUS() {
static int WIFI_CONNECT_STATUS() {
if (WiFi.STA.connected()) {
if (WiFi.STA.hasIP()) {
return 7;
@@ -65,7 +65,7 @@ int WIFI_CONNECT_STATUS() {
#endif // if defined(ESP32)
String getReplacementString(const String& format, const String& s) {
static String getReplacementString(const String& format, const String& s) {
int startpos = s.indexOf(format);
int endpos = s.indexOf('%', startpos + 1);
if (endpos == -1) {
@@ -87,19 +87,19 @@ String getReplacementString(const String& format, const String& s) {
return R;
}
void replSunRiseTimeString(const String& format, String& s, boolean useURLencode) {
static void replSunRiseTimeString(const String& format, String& s, boolean useURLencode) {
const String R(getReplacementString(format, s));
repl(R, node_time.getSunriseTimeString(':', ESPEasy_time::getSecOffset(R)), s, useURLencode);
}
void replSunSetTimeString(const String& format, String& s, boolean useURLencode) {
static void replSunSetTimeString(const String& format, String& s, boolean useURLencode) {
const String R(getReplacementString(format, s));
repl(R, node_time.getSunsetTimeString(':', ESPEasy_time::getSecOffset(R)), s, useURLencode);
}
String timeReplacement_leadZero(int value)
static String timeReplacement_leadZero(int value)
{
char valueString[5] = { 0 };
@@ -108,7 +108,7 @@ String timeReplacement_leadZero(int value)
}
// FIXME TD-er: Try to match these with StringProvider::getValue
LabelType::Enum SystemVariables2LabelType(SystemVariables::Enum enumval) {
static LabelType::Enum SystemVariables2LabelType(SystemVariables::Enum enumval) {
LabelType::Enum label = LabelType::MAX_LABEL;
switch (enumval)
@@ -327,7 +327,7 @@ String SystemVariables::getSystemVariable(SystemVariables::Enum enumval) {
while (__pos__ != -1) { (S((T_str), s, useURLencode)); __pos__ = s.indexOf(T_str, __pos__ + 1);}
// Parse %vN% to replace ESPEasy variables
bool parse_pct_v_num_pct(String& s, boolean useURLencode, int start_pos)
static bool parse_pct_v_num_pct(String& s, boolean useURLencode, int start_pos)
{
const String key_prefix = F("%v");
int v_index = s.indexOf(key_prefix, start_pos);
+1 -1
View File
@@ -27,7 +27,7 @@
// 1=Comfortable
// 2=Dry
// 3=Wet
int humStatDomoticz(struct EventStruct *event, uint8_t rel_index) {
static int humStatDomoticz(struct EventStruct *event, uint8_t rel_index) {
userVarIndex_t userVarIndex = event->BaseVarIndex + rel_index;
if (validTaskVarIndex(rel_index) && validUserVarIndex(userVarIndex)) {
@@ -7,14 +7,6 @@
# include "../Helpers/_CPlugin_Helper.h"
// HUM_STAT can be one of:
// 0=Normal
// 1=Comfortable
// 2=Dry
// 3=Wet
int humStatDomoticz(struct EventStruct *event,
uint8_t rel_index);
int mapRSSItoDomoticz();
+1 -1
View File
@@ -84,7 +84,7 @@ bool safeReadStringUntil(Stream & input,
#ifndef BUILD_NO_DEBUG
void log_connecting_to(const __FlashStringHelper *prefix, cpluginID_t cpluginID, ControllerSettingsStruct& ControllerSettings) {
static void log_connecting_to(const __FlashStringHelper *prefix, cpluginID_t cpluginID, ControllerSettingsStruct& ControllerSettings) {
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
addLogMove(LOG_LEVEL_DEBUG,
strformat(F("%s%s connecting to %s"),
-4
View File
@@ -32,10 +32,6 @@ bool safeReadStringUntil(Stream & input,
unsigned int timeout = 1000);
#ifndef BUILD_NO_DEBUG
void log_connecting_to(const __FlashStringHelper * prefix, cpluginID_t cpluginID, ControllerSettingsStruct& ControllerSettings);
#endif // ifndef BUILD_NO_DEBUG
bool count_connection_results(bool success, const __FlashStringHelper * prefix, cpluginID_t cpluginID, uint64_t statisticsTimerStart);
#if FEATURE_HTTP_CLIENT
+259 -214
View File
@@ -378,21 +378,21 @@ int Plugin_QueryVType_BinarySensorInv(uint8_t value_nr) {
return static_cast<int>(Sensor_VType::SENSOR_TYPE_SWITCH_INVERTED) | Sensor_VType_CAN_SET;
}
int Plugin_QueryVType_Analog(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_ANALOG_ONLY); }
int Plugin_QueryVType_Analog(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_ANALOG_ONLY); }
int Plugin_QueryVType_CO2(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_CO2_ONLY); }
int Plugin_QueryVType_CO2(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_CO2_ONLY); }
int Plugin_QueryVType_Distance(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY); }
int Plugin_QueryVType_Distance(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_DISTANCE_ONLY); }
int Plugin_QueryVType_DustPM2_5(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY); }
int Plugin_QueryVType_DustPM2_5(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_DUSTPM2_5_ONLY); }
int Plugin_QueryVType_Lux(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_LUX_ONLY); }
int Plugin_QueryVType_Lux(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_LUX_ONLY); }
int Plugin_QueryVType_Temperature(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_TEMP_ONLY); }
int Plugin_QueryVType_Temperature(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_TEMP_ONLY); }
int Plugin_QueryVType_Weight(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY); }
int Plugin_QueryVType_Weight(uint8_t value_nr) { return static_cast<int>(Sensor_VType::SENSOR_TYPE_WEIGHT_ONLY); }
String makeHomeAssistantCompliantName(const String& name) { return ESPEasy::net::makeRFCCompliantName(name, '_', '_', 0); }
static String makeHomeAssistantCompliantName(const String& name) { return ESPEasy::net::makeRFCCompliantName(name, '_', '_', 0); }
# if FEATURE_MQTT_DEVICECLASS
const char mqtt_binary_deviceclass_names[] PROGMEM =
@@ -412,7 +412,7 @@ String MQTT_binary_deviceClassName(int devClassIndex) {
return result;
}
int MQTT_binary_deviceClassIndex(const String& deviceClassName) {
static int MQTT_binary_deviceClassIndex(const String& deviceClassName) {
return GetCommandCode(deviceClassName.c_str(), mqtt_binary_deviceclass_names);
}
@@ -468,49 +468,234 @@ const __FlashStringHelper* MQTT_sensor_StateClass(uint8_t index,
# endif // if FEATURE_MQTT_STATE_CLASS
bool MQTT_SendAutoDiscovery(controllerIndex_t ControllerIndex, cpluginID_t CPluginID) {
bool success = true;
static String MQTT_DiscoveryBuildValueTopic(const String & topic,
struct EventStruct *event,
uint8_t taskValueIndex,
const __FlashStringHelper*deviceClass,
const String & uniqueId,
const String & elementId,
const String & valueName) {
String tmpTopic(topic);
MakeControllerSettings(ControllerSettings); // -V522
# if FEATURE_STRING_VARIABLES
if (!AllocatedControllerSettings()) {
return false;
if (taskValueIndex >= VARS_PER_TASK) {
parseValNameVariable(tmpTopic, valueName, false);
} else
# endif // if FEATURE_STRING_VARIABLES
{
parseSingleControllerVariable(tmpTopic, event, taskValueIndex, false);
}
LoadControllerSettings(ControllerIndex, *ControllerSettings);
parseDeviceClassVariable(tmpTopic, deviceClass, false);
parseUniqueIdVariable(tmpTopic, uniqueId, false);
parseElementIdVariable(tmpTopic, elementId, false);
parseControllerVariables(tmpTopic, event, false); // Replace this last
if (ControllerSettings->mqtt_autoDiscovery()
while (tmpTopic.endsWith(F("/"))) {
tmpTopic = tmpTopic.substring(0, tmpTopic.length() - 1);
}
// && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != 0)
&& (ControllerSettings->MqttAutoDiscoveryTopic[0] != 0)) {
# ifndef BUILD_NO_DEBUG
return tmpTopic;
}
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, concat(strformat(F("MQTT : AutoDiscovery for Controller %d CPlugin %d"),
ControllerIndex + 1, CPluginID),
validTaskIndex(mqttDiscoverOnlyTask) ?
strformat(F(", Task %d"), mqttDiscoverOnlyTask + 1) :
EMPTY_STRING));
}
# endif // ifndef BUILD_NO_DEBUG
static String MQTT_TaskValueUniqueName(const String& taskName,
const String& valueName) {
String uniqueId = strformat(F("%s_%s_%s"),
makeHomeAssistantCompliantName(Settings.getHostname()).c_str(),
taskName.c_str(),
valueName.c_str());
uniqueId.toLowerCase();
return uniqueId;
}
// Dispatch autoDiscovery per supported CPlugin
switch (CPluginID)
static bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex,
const String & topic,
const String & discoveryMessage,
taskIndex_t x,
uint8_t v,
bool retainDsc) {
bool result = false;
// Send each discovery message separate
result = MQTTpublish(ControllerIndex, INVALID_TASK_INDEX, topic.c_str(), discoveryMessage.c_str(), retainDsc);
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery %d Task %d '%s': disc.topic: %s"),
result, x + 1, getTaskDeviceName(x).c_str(), topic.c_str()));
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery payload: %s"),
discoveryMessage.c_str()));
}
# endif // ifndef BUILD_NO_DEBUG
return result;
}
static bool MQTT_DiscoveryPublishWithStatusAndSet(
uint8_t taskValue,
const String & valueName,
controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings,
const __FlashStringHelper*componentClass,
const String & deviceClass,
const String & unitOfMeasure,
struct EventStruct *event,
const String & deviceElement,
const String & stateClass,
bool success,
bool hasSet,
bool hasIcon,
const String & elementName,
const String & elementId,
bool sendTrigger)
{
if (!valueName.isEmpty()) {
const String taskName = makeHomeAssistantCompliantName(getTaskDeviceName(event->TaskIndex));
const String valName = makeHomeAssistantCompliantName(valueName);
const String uniqueId = elementName.isEmpty() ? MQTT_TaskValueUniqueName(taskName, valName)
: Settings.MQTTDiscoverGroupInclTaskname()
? strformat(F("%s_%s_%s"), elementId.c_str(), taskName.c_str(), valName.c_str())
: strformat(F("%s_%s"), elementId.c_str(), valName.c_str());
String message;
{
case 5: // CPLUGIN_ID_005 : Home assistant/openHAB
success = MQTT_HomeAssistant_SendAutoDiscovery(ControllerIndex, *ControllerSettings);
break;
}
}
const String publish = MQTT_DiscoveryBuildValueTopic(ControllerSettings.Publish,
event,
taskValue,
componentClass,
uniqueId,
elementId,
valName);
if (sendTrigger) {
// triggerMessage
message = strformat(F("{\"atype\":\"trigger\",\"t\":\"%s\","
"\"p\":\"device_automation\","
"\"type\":\"button_short_press\"," // FIXME ?
"\"stype\":\"switch_1\"" // FIXME ?
"%s}"), // deviceElement is used to pass in the TriggerState
publish.c_str(), deviceElement.c_str());
} else {
// discoveryMessage
const String withSet = hasSet ? F(",\"cmd_t\":\"~/set\"") : EMPTY_STRING;
const String schema = hasSet ? EMPTY_STRING : "\"schema\":\"basic\",";
const String devOrIcon = hasIcon ? F("ic") : F("dev_cla");
const String withUoM = unitOfMeasure.isEmpty() ? EMPTY_STRING :
strformat(F(",\"unit_of_meas\":\"%s\""), unitOfMeasure.c_str());
const String stateJson = stateClass.isEmpty() ? EMPTY_STRING :
strformat(F(",\"stat_cla\":\"%s\""), stateClass.c_str());
message = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\",%s"
"\"%s\":\"%s\"%s%s%s,\"stat_t\":\"~\""
"%s}"), // deviceElement last
publish.c_str(), taskName.c_str(), valName.c_str(), uniqueId.c_str(), schema.c_str(),
devOrIcon.c_str(), deviceClass.c_str(), withUoM.c_str(), stateJson.c_str(), withSet.c_str(),
deviceElement.c_str());
}
}
const bool retainDsc = ControllerSettings.mqtt_retainDiscovery();
String topic;
{
const String discoveryUrl = MQTT_DiscoveryBuildValueTopic(ControllerSettings.MqttAutoDiscoveryTopic,
event,
taskValue,
componentClass,
uniqueId,
elementId,
valName);
const String discoveryConfig(parseStringKeepCase(ControllerSettings.MqttAutoDiscoveryConfig, 1, '|'));
topic = discoveryConfig.isEmpty()
? concat(discoveryUrl, F("/config"))
: concat(discoveryUrl, discoveryConfig);
}
return MQTT_DiscoveryPublish(ControllerIndex,
topic,
message,
event->TaskIndex,
taskValue,
retainDsc);
}
return success;
}
static bool MQTT_DiscoveryPublishWithStatusAndSet(
uint8_t taskValue,
const String & valueName,
controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings,
const __FlashStringHelper*componentClass,
const String & deviceClass,
const String & unitOfMeasure,
struct EventStruct *event,
const String & deviceElement,
const String & stateClass,
bool success,
bool hasSet,
bool hasIcon,
const String & elementName,
const String & elementId)
{
return MQTT_DiscoveryPublishWithStatusAndSet(
taskValue,
valueName,
ControllerIndex,
ControllerSettings,
componentClass,
deviceClass,
unitOfMeasure,
event,
deviceElement,
stateClass,
success,
hasSet,
hasIcon,
elementName,
elementId,
false);
}
static String MQTT_DiscoveryHelperGetValueName(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem) {
return
# if FEATURE_STRING_VARIABLES
discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.varName :
# endif // if FEATURE_STRING_VARIABLES
getTaskValueName(taskIndex, taskVarIndex);
}
static String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem,
const String& defaultUoM) {
return
# if FEATURE_TASKVALUE_UNIT_OF_MEASURE
# if FEATURE_STRING_VARIABLES
discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom :
# endif // if FEATURE_STRING_VARIABLES
toUnitOfMeasureName(Cache.getTaskVarUnitOfMeasure(taskIndex, taskVarIndex), defaultUoM);
# else // FEATURE_TASKVALUE_UNIT_OF_MEASURE
# if FEATURE_STRING_VARIABLES
discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom :
# endif // if FEATURE_STRING_VARIABLES
defaultUoM;
# endif // FEATURE_TASKVALUE_UNIT_OF_MEASURE
}
static String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem)
{
return MQTT_DiscoveryHelperGetValueUoM(taskIndex, taskVarIndex, discoveryItem, EMPTY_STRING);
}
/********************************************************
* Send MQTT AutoDiscovery in Home Assistant format
*******************************************************/
bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings) {
static bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings) {
bool success = false;
// Send plugin info
@@ -934,6 +1119,44 @@ bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIn
return success;
}
bool MQTT_SendAutoDiscovery(controllerIndex_t ControllerIndex, cpluginID_t CPluginID) {
bool success = true;
MakeControllerSettings(ControllerSettings); // -V522
if (!AllocatedControllerSettings()) {
return false;
}
LoadControllerSettings(ControllerIndex, *ControllerSettings);
if (ControllerSettings->mqtt_autoDiscovery()
// && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != 0)
&& (ControllerSettings->MqttAutoDiscoveryTopic[0] != 0)) {
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, concat(strformat(F("MQTT : AutoDiscovery for Controller %d CPlugin %d"),
ControllerIndex + 1, CPluginID),
validTaskIndex(mqttDiscoverOnlyTask) ?
strformat(F(", Task %d"), mqttDiscoverOnlyTask + 1) :
EMPTY_STRING));
}
# endif // ifndef BUILD_NO_DEBUG
// Dispatch autoDiscovery per supported CPlugin
switch (CPluginID)
{
case 5: // CPLUGIN_ID_005 : Home assistant/openHAB
success = MQTT_HomeAssistant_SendAutoDiscovery(ControllerIndex, *ControllerSettings);
break;
}
}
return success;
}
bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
std::vector<DiscoveryItem>& discoveryItems,
int valueCount,
@@ -1017,184 +1240,6 @@ bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
return discoveryItems.size() != orgLen; // Something added?
}
String MQTT_TaskValueUniqueName(const String& taskName,
const String& valueName) {
String uniqueId = strformat(F("%s_%s_%s"),
makeHomeAssistantCompliantName(Settings.getHostname()).c_str(),
taskName.c_str(),
valueName.c_str());
uniqueId.toLowerCase();
return uniqueId;
}
String MQTT_DiscoveryBuildValueTopic(const String & topic,
struct EventStruct *event,
uint8_t taskValueIndex,
const __FlashStringHelper*deviceClass,
const String & uniqueId,
const String & elementId,
const String & valueName) {
String tmpTopic(topic);
# if FEATURE_STRING_VARIABLES
if (taskValueIndex >= VARS_PER_TASK) {
parseValNameVariable(tmpTopic, valueName, false);
} else
# endif // if FEATURE_STRING_VARIABLES
{
parseSingleControllerVariable(tmpTopic, event, taskValueIndex, false);
}
parseDeviceClassVariable(tmpTopic, deviceClass, false);
parseUniqueIdVariable(tmpTopic, uniqueId, false);
parseElementIdVariable(tmpTopic, elementId, false);
parseControllerVariables(tmpTopic, event, false); // Replace this last
while (tmpTopic.endsWith(F("/"))) {
tmpTopic = tmpTopic.substring(0, tmpTopic.length() - 1);
}
return tmpTopic;
}
bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex,
const String & topic,
const String & discoveryMessage,
taskIndex_t x,
uint8_t v,
bool retainDsc) {
bool result = false;
// Send each discovery message separate
result = MQTTpublish(ControllerIndex, INVALID_TASK_INDEX, topic.c_str(), discoveryMessage.c_str(), retainDsc);
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery %d Task %d '%s': disc.topic: %s"),
result, x + 1, getTaskDeviceName(x).c_str(), topic.c_str()));
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery payload: %s"),
discoveryMessage.c_str()));
}
# endif // ifndef BUILD_NO_DEBUG
return result;
}
bool MQTT_DiscoveryPublishWithStatusAndSet(uint8_t taskValue,
const String & valueName,
controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings,
const __FlashStringHelper*componentClass,
const String & deviceClass,
const String & unitOfMeasure,
struct EventStruct *event,
const String & deviceElement,
const String & stateClass,
bool success,
bool hasSet,
bool hasIcon,
const String & elementName,
const String & elementId,
bool sendTrigger) {
if (!valueName.isEmpty()) {
const String taskName = makeHomeAssistantCompliantName(getTaskDeviceName(event->TaskIndex));
const String valName = makeHomeAssistantCompliantName(valueName);
const String uniqueId = elementName.isEmpty() ? MQTT_TaskValueUniqueName(taskName, valName)
: Settings.MQTTDiscoverGroupInclTaskname()
? strformat(F("%s_%s_%s"), elementId.c_str(), taskName.c_str(), valName.c_str())
: strformat(F("%s_%s"), elementId.c_str(), valName.c_str());
String message;
{
const String publish = MQTT_DiscoveryBuildValueTopic(ControllerSettings.Publish,
event,
taskValue,
componentClass,
uniqueId,
elementId,
valName);
if (sendTrigger) {
// triggerMessage
message = strformat(F("{\"atype\":\"trigger\",\"t\":\"%s\","
"\"p\":\"device_automation\","
"\"type\":\"button_short_press\"," // FIXME ?
"\"stype\":\"switch_1\"" // FIXME ?
"%s}"), // deviceElement is used to pass in the TriggerState
publish.c_str(), deviceElement.c_str());
} else {
// discoveryMessage
const String withSet = hasSet ? F(",\"cmd_t\":\"~/set\"") : EMPTY_STRING;
const String schema = hasSet ? EMPTY_STRING : "\"schema\":\"basic\",";
const String devOrIcon = hasIcon ? F("ic") : F("dev_cla");
const String withUoM = unitOfMeasure.isEmpty() ? EMPTY_STRING :
strformat(F(",\"unit_of_meas\":\"%s\""), unitOfMeasure.c_str());
const String stateJson = stateClass.isEmpty() ? EMPTY_STRING :
strformat(F(",\"stat_cla\":\"%s\""), stateClass.c_str());
message = strformat(F("{\"~\":\"%s\",\"name\":\"%s %s\",\"uniq_id\":\"%s\",%s"
"\"%s\":\"%s\"%s%s%s,\"stat_t\":\"~\""
"%s}"), // deviceElement last
publish.c_str(), taskName.c_str(), valName.c_str(), uniqueId.c_str(), schema.c_str(),
devOrIcon.c_str(), deviceClass.c_str(), withUoM.c_str(), stateJson.c_str(), withSet.c_str(),
deviceElement.c_str());
}
}
const bool retainDsc = ControllerSettings.mqtt_retainDiscovery();
String topic;
{
const String discoveryUrl = MQTT_DiscoveryBuildValueTopic(ControllerSettings.MqttAutoDiscoveryTopic,
event,
taskValue,
componentClass,
uniqueId,
elementId,
valName);
const String discoveryConfig(parseStringKeepCase(ControllerSettings.MqttAutoDiscoveryConfig, 1, '|'));
topic = discoveryConfig.isEmpty()
? concat(discoveryUrl, F("/config"))
: concat(discoveryUrl, discoveryConfig);
}
return MQTT_DiscoveryPublish(ControllerIndex,
topic,
message,
event->TaskIndex,
taskValue,
retainDsc);
}
return success;
}
String MQTT_DiscoveryHelperGetValueName(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem) {
return
# if FEATURE_STRING_VARIABLES
discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.varName :
# endif // if FEATURE_STRING_VARIABLES
getTaskValueName(taskIndex, taskVarIndex);
}
String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem,
const String& defaultUoM) {
return
# if FEATURE_TASKVALUE_UNIT_OF_MEASURE
# if FEATURE_STRING_VARIABLES
discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom :
# endif // if FEATURE_STRING_VARIABLES
toUnitOfMeasureName(Cache.getTaskVarUnitOfMeasure(taskIndex, taskVarIndex), defaultUoM);
# else // FEATURE_TASKVALUE_UNIT_OF_MEASURE
# if FEATURE_STRING_VARIABLES
discoveryItem.varIndex >= VARS_PER_TASK ? discoveryItem.uom :
# endif // if FEATURE_STRING_VARIABLES
defaultUoM;
# endif // FEATURE_TASKVALUE_UNIT_OF_MEASURE
}
# endif // if FEATURE_MQTT_DISCOVER
#endif // if FEATURE_MQTT
-46
View File
@@ -33,13 +33,10 @@ int Plugin_QueryVType_Lux(uint8_t value_nr);
int Plugin_QueryVType_Temperature(uint8_t value_nr);
int Plugin_QueryVType_Weight(uint8_t value_nr);
String makeHomeAssistantCompliantName(const String& name);
# if FEATURE_MQTT_DEVICECLASS
String MQTT_binary_deviceClassName(int devClassIndex);
bool MQTT_binary_deviceClassTwoWay(int devClassIndex);
bool MQTT_binary_deviceClassSwitch(int devClassIndex);
int MQTT_binary_deviceClassIndex(const String& deviceClassName);
# endif // if FEATURE_MQTT_DEVICECLASS
# if FEATURE_MQTT_STATE_CLASS
const __FlashStringHelper* MQTT_sensor_StateClass(uint8_t index,
@@ -68,54 +65,11 @@ struct DiscoveryItem {
bool MQTT_SendAutoDiscovery(controllerIndex_t ControllerIndex,
cpluginID_t CPluginID);
bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings);
bool MQTT_DiscoveryGetDeviceVType(taskIndex_t TaskIndex,
std::vector<DiscoveryItem>& discoveryItems,
int valueCount,
String & deviceClass);
String MQTT_TaskValueUniqueName(const String& taskName,
const String& valueName);
String MQTT_DiscoveryBuildValueTopic(const String & topic,
struct EventStruct *event,
uint8_t taskValueIndex,
const __FlashStringHelper*deviceClass,
const String & uniqueId,
const String & elementId,
const String & valueName);
bool MQTT_DiscoveryPublish(controllerIndex_t ControllerIndex,
const String & topic,
const String & discoveryMessage,
taskIndex_t x,
uint8_t v,
bool retained = false);
bool MQTT_DiscoveryPublishWithStatusAndSet(uint8_t taskValue,
const String & valueName,
controllerIndex_t ControllerIndex,
ControllerSettingsStruct& ControllerSettings,
const __FlashStringHelper*componentClass,
const String & deviceClass,
const String & unitOfMeasure,
struct EventStruct *event,
const String & deviceElement,
const String & stateClass,
bool success,
bool hasSet,
bool hasIcon,
const String & elementName,
const String & elementId,
bool sendTrigger = false);
String MQTT_DiscoveryHelperGetValueName(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem);
String MQTT_DiscoveryHelperGetValueUoM(taskIndex_t taskIndex,
uint8_t taskVarIndex,
DiscoveryItem discoveryItem,
const String& defaultUoM = EMPTY_STRING);
# endif // if FEATURE_MQTT_DISCOVER
#endif // if FEATURE_MQTT
+2 -2
View File
@@ -120,7 +120,7 @@ String getControllerParameterInternalName(protocolIndex_t ProtocolIndex, Control
return getControllerParameterName(ProtocolIndex, parameterIdx, displayName, isAlternative);
}
String getControllerParameterDisplayName(protocolIndex_t ProtocolIndex, ControllerSettingsStruct::VarType parameterIdx, bool& isAlternative) {
static String getControllerParameterDisplayName(protocolIndex_t ProtocolIndex, ControllerSettingsStruct::VarType parameterIdx, bool& isAlternative) {
bool displayName = true;
return getControllerParameterName(ProtocolIndex, parameterIdx, displayName, isAlternative);
@@ -142,7 +142,7 @@ void addControllerEnabledForm(controllerIndex_t controllerindex) {
}
#if FEATURE_MQTT_TLS || FEATURE_HTTP_TLS
void addCertificateFileNote(const ControllerSettingsStruct& ControllerSettings, const String& description, TLS_types tls_type) {
static void addCertificateFileNote(const ControllerSettingsStruct& ControllerSettings, const String& description, TLS_types tls_type) {
const String certFile = ControllerSettings.getCertificateFilename(tls_type);
if (!certFile.isEmpty())
@@ -17,8 +17,6 @@ String getControllerParameterName(protocolIndex_t ProtocolInde
String getControllerParameterInternalName(protocolIndex_t ProtocolIndex, ControllerSettingsStruct::VarType parameterIdx);
String getControllerParameterDisplayName(protocolIndex_t ProtocolIndex, ControllerSettingsStruct::VarType parameterIdx, bool& isAlternative);
void addControllerEnabledForm(controllerIndex_t controllerindex);
void addControllerParameterForm(const ControllerSettingsStruct& ControllerSettings, controllerIndex_t controllerindex, ControllerSettingsStruct::VarType varType);
+2 -2
View File
@@ -60,7 +60,7 @@ void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, int pconfigI
sensorTypeHelper_webformLoad(event, pconfigIndex, optionCount, optionValues);
}
void sensorTypeHelper_Selector(const String& id, int optionCount, const uint8_t options[], Sensor_VType choice) {
static void sensorTypeHelper_Selector(const String& id, int optionCount, const uint8_t options[], Sensor_VType choice) {
addSelector_Head(id);
for (uint8_t x = 0; x < optionCount; x++)
@@ -85,7 +85,7 @@ const char value_type_categories[] PROGMEM =
"Other|" // 1031
;
String toValueTypeCategory(const uint32_t valueType) {
static String toValueTypeCategory(const uint32_t valueType) {
char tmp[12]{};
String result;
@@ -9,7 +9,6 @@ void sensorTypeHelper_webformLoad_allTypes(struct EventStruct *event, int pconfi
void sensorTypeHelper_webformLoad_simple(struct EventStruct *event, int pconfigIndex);
void sensorTypeHelper_Selector(const String& id, int optionCount, const uint8_t options[], Sensor_VType choice);
#if FEATURE_CUSTOM_TASKVAR_VTYPE
void sensorTypeCategoriesHelper_Selector(const String& id,
int optionCount,
+109 -102
View File
@@ -20,6 +20,115 @@
# endif // if FEATURE_EMAIL_TLS
static bool getNextMailAddress(const String& data, String& address, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
const int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if ((data.charAt(i) == ',') || (i == maxIndex)) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
if (found > index) {
address = data.substring(strIndex[0], strIndex[1]);
return true;
}
return false;
}
static bool NPlugin_001_MTA(WiFiClient& client, const String& aStr, uint16_t aWaitForPattern, uint16_t timeout)
{
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
addLog(LOG_LEVEL_DEBUG, strformat(
F("NPlugin_001_MTA: Waitfor: %u Timeout: %u ms Send: '%s'"),
aWaitForPattern,
timeout,
aStr.c_str()));
}
# endif // ifndef BUILD_NO_DEBUG
if (aStr.length()) {
client.PR_9453_FLUSH_TO_CLEAR(); // have to send msg to server so flush data first
client.println(aStr);
}
// Wait For Response
const uint32_t timer = millis() + timeout;
backgroundtasks();
do { // FIXME TD-er: Why this while loop??? makes no sense as it will only be run once
delay(0);
String line;
safeReadStringUntil(client, line, '\n', 1024); // , timeout);
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
addLogMove(LOG_LEVEL_DEBUG, concat(F("NPlugin_001_MTA: read line: "), line));
}
# endif // ifndef BUILD_NO_DEBUG
// response could be like: '220 domain', '220-domain','220+domain'
const String pattern_str_space = strformat(F("%d "), aWaitForPattern);
const String pattern_str_minus = strformat(F("%d-"), aWaitForPattern);
const String pattern_str_plus = strformat(F("%d+"), aWaitForPattern);
const bool patternFound = line.indexOf(pattern_str_space) >= 0
|| line.indexOf(pattern_str_minus) >= 0
|| line.indexOf(pattern_str_plus) >= 0;
if (patternFound) {
return true;
}
} while (!timeOutReached(timer));
if (timeOutReached(timer)) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
addLogMove(LOG_LEVEL_ERROR,
concat(F("NPlugin_001_MTA: timeout. "), aStr));
}
}
return false;
}
static bool NPlugin_001_Auth(WiFiClient& client, const String& user, const String& pass, uint16_t timeout)
{
if (user.isEmpty() || pass.isEmpty()) {
// No user/password given.
return true;
}
base64 encoder;
bool success = true;
if (!NPlugin_001_MTA(client, F("AUTH LOGIN"), 334, timeout)) { success = false; }
if (!NPlugin_001_MTA(client, encoder.encode(user), 334, timeout)) { success = false; }
if (!NPlugin_001_MTA(client, encoder.encode(pass), 235, timeout)) { success = false; }
#ifndef BUILD_NO_DEBUG
if (success) {
addLog(LOG_LEVEL_INFO, F("Email: Credentials Accepted"));
}
#endif
return success;
}
bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, String& subject, String& body)
{
bool myStatus = false;
@@ -383,108 +492,6 @@ bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings, St
return myStatus;
}
bool NPlugin_001_Auth(WiFiClient& client, const String& user, const String& pass, uint16_t timeout)
{
if (user.isEmpty() || pass.isEmpty()) {
// No user/password given.
return true;
}
base64 encoder;
bool success = true;
if (!NPlugin_001_MTA(client, F("AUTH LOGIN"), 334, timeout)) { success = false; }
if (!NPlugin_001_MTA(client, encoder.encode(user), 334, timeout)) { success = false; }
if (!NPlugin_001_MTA(client, encoder.encode(pass), 235, timeout)) { success = false; }
#ifndef BUILD_NO_DEBUG
if (success) {
addLog(LOG_LEVEL_INFO, F("Email: Credentials Accepted"));
}
#endif
return success;
}
bool NPlugin_001_MTA(WiFiClient& client, const String& aStr, uint16_t aWaitForPattern, uint16_t timeout)
{
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
addLog(LOG_LEVEL_DEBUG, strformat(
F("NPlugin_001_MTA: Waitfor: %u Timeout: %u ms Send: '%s'"),
aWaitForPattern,
timeout,
aStr.c_str()));
}
# endif // ifndef BUILD_NO_DEBUG
if (aStr.length()) {
client.PR_9453_FLUSH_TO_CLEAR(); // have to send msg to server so flush data first
client.println(aStr);
}
// Wait For Response
const uint32_t timer = millis() + timeout;
backgroundtasks();
do { // FIXME TD-er: Why this while loop??? makes no sense as it will only be run once
delay(0);
String line;
safeReadStringUntil(client, line, '\n', 1024); // , timeout);
# ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
addLogMove(LOG_LEVEL_DEBUG, concat(F("NPlugin_001_MTA: read line: "), line));
}
# endif // ifndef BUILD_NO_DEBUG
// response could be like: '220 domain', '220-domain','220+domain'
const String pattern_str_space = strformat(F("%d "), aWaitForPattern);
const String pattern_str_minus = strformat(F("%d-"), aWaitForPattern);
const String pattern_str_plus = strformat(F("%d+"), aWaitForPattern);
const bool patternFound = line.indexOf(pattern_str_space) >= 0
|| line.indexOf(pattern_str_minus) >= 0
|| line.indexOf(pattern_str_plus) >= 0;
if (patternFound) {
return true;
}
} while (!timeOutReached(timer));
if (timeOutReached(timer)) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
addLogMove(LOG_LEVEL_ERROR,
concat(F("NPlugin_001_MTA: timeout. "), aStr));
}
}
return false;
}
bool getNextMailAddress(const String& data, String& address, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
const int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if ((data.charAt(i) == ',') || (i == maxIndex)) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
if (found > index) {
address = data.substring(strIndex[0], strIndex[1]);
return true;
}
return false;
}
#endif // ifdef USES_N001
@@ -20,17 +20,6 @@
bool NPlugin_001_send(const NotificationSettingsStruct& notificationsettings,
String & subject,
String & body);
bool NPlugin_001_Auth(WiFiClient & client,
const String& user,
const String& pass,
uint16_t timeout);
bool NPlugin_001_MTA(WiFiClient & client,
const String& aStr,
uint16_t aWaitForPattern,
uint16_t timeout);
bool getNextMailAddress(const String& data,
String & address,
int index);
#endif // ifdef USES_N001
+178 -159
View File
@@ -8,7 +8,7 @@
#include "../WebServer/HTML_wrappers.h"
#include "../WebServer/LoadFromFS.h"
String generate_external_URL(const String& fname, bool isEmbedded) {
static String generate_external_URL(const String& fname, bool isEmbedded) {
if (isEmbedded || fileExists(fname)) {
// Generate some URL indicating static files which will need to be served with some cache-control header
return concat(F("static_"), Cache.fileCacheClearMoment) + '_' + fname;
@@ -16,52 +16,54 @@ String generate_external_URL(const String& fname, bool isEmbedded) {
#if FEATURE_ALTERNATIVE_CDN_URL
String cdn = get_CDN_url_custom();
if (!cdn.isEmpty()) {
cdn = parseTemplate(cdn); // Replace system variables.
return concat(cdn, fname); // cdn.endsWith('/') check done at save
}
}
#endif // if FEATURE_ALTERNATIVE_CDN_URL
return concat(get_CDN_url_prefix(), fname);
}
void serve_CDN_CSS(const __FlashStringHelper * fname, const __FlashStringHelper * fname_alt, bool isEmbedded) {
static void serve_CDN_CSS(const __FlashStringHelper *fname, const __FlashStringHelper *fname_alt, bool isEmbedded) {
const String url = generate_external_URL(fname, isEmbedded);
// FIXME TD-er: For now just retry loading the same as failed loading the embedded one
// may slow down next page loads until the browser finally was able to fetch the embedded one.
const String url2 = generate_external_URL(fname, isEmbedded);
// const String url2 = generate_external_URL(fname_alt, !isEmbedded);
// const String url2 = generate_external_URL(fname_alt, !isEmbedded);
// Use 'onerror' to try to reload the CSS when first attempt loading failed
// See: https://developer.mozilla.org/en-US/docs/Web/API/Window/error_event#element.onerror
addHtml(strformat(
F("<link rel=\"stylesheet\" href=\"%s\" onerror=\"this.onerror=null;this.href='%s';\" />"),
url.c_str(),
url2.c_str()
));
F("<link rel=\"stylesheet\" href=\"%s\" onerror=\"this.onerror=null;this.href='%s';\" />"),
url.c_str(),
url2.c_str()
));
// <link rel="stylesheet" href="%s" onerror="this.onerror=null;this.href='%s';" />
/*
// Delay loading CSS till after page has loaded.
// Disabled as it adds 'flickering' to the page loading
addHtml(strformat(
F("<link rel=\"preload\" href=\"%s\" as=\"style\" onload=\"this.onload=null;this.rel='stylesheet'\"><noscript><link rel=\"stylesheet\" href=\"%s\"></noscript>"),
url.c_str(), url.c_str()
));
*/
// Delay loading CSS till after page has loaded.
// Disabled as it adds 'flickering' to the page loading
addHtml(strformat(
F("<link rel=\"preload\" href=\"%s\" as=\"style\" onload=\"this.onload=null;this.rel='stylesheet'\"><noscript><link rel=\"stylesheet\"
href=\"%s\"></noscript>"),
url.c_str(), url.c_str()
));
*/
}
void serve_CDN_CSS(const __FlashStringHelper * fname, bool isEmbedded) {
serve_CDN_CSS(fname, fname, isEmbedded);
}
static void serve_CDN_CSS(const __FlashStringHelper *fname, bool isEmbedded) { serve_CDN_CSS(fname, fname, isEmbedded); }
void serve_CDN_JS(const __FlashStringHelper * fname,
const __FlashStringHelper * script_arg,
bool useDefer) {
static void serve_CDN_JS(const __FlashStringHelper *fname,
const __FlashStringHelper *script_arg,
bool useDefer) {
addHtml(F("<script"));
if (useDefer) {
addHtml(F(" defer"));
}
@@ -72,36 +74,37 @@ void serve_CDN_JS(const __FlashStringHelper * fname,
html_add_script_end();
}
void serve_CSS(CSSfiles_e cssfile) {
const __FlashStringHelper * url = F("");
const __FlashStringHelper *url = F("");
#if !defined(WEBSERVER_CSS)
bool useCDN = true;
#else
bool useCDN = false;
#endif
#endif // if !defined(WEBSERVER_CSS)
switch (cssfile) {
switch (cssfile)
{
case CSSfiles_e::ESPEasy_default:
// Send CSS in chunks
#if defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS)
useCDN = false;
#endif
#endif
url = F("espeasy_default.min.css");
break;
#if FEATURE_RULES_EASY_COLOR_CODE
case CSSfiles_e::EasyColorCode_codemirror:
url = F("codemirror.min.css");
url = F("codemirror.min.css");
useCDN = true;
break;
#endif
#endif // if FEATURE_RULES_EASY_COLOR_CODE
default:
return;
return;
}
const __FlashStringHelper * cssFile =
(cssfile == CSSfiles_e::ESPEasy_default) ?
F("esp.css") : url;
const __FlashStringHelper *cssFile =
(cssfile == CSSfiles_e::ESPEasy_default) ?
F("esp.css") : url;
if (fileExists(cssFile))
{
@@ -109,18 +112,20 @@ void serve_CSS(CSSfiles_e cssfile) {
return;
}
#if !(defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS)) || FEATURE_RULES_EASY_COLOR_CODE
if (useCDN) {
serve_CDN_CSS(url, false);
return;
}
#endif
#endif // if !(defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS)) || FEATURE_RULES_EASY_COLOR_CODE
#if defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS)
if (cssfile == CSSfiles_e::ESPEasy_default) {
serve_CDN_CSS(cssFile, url, true);
} else {
serve_CDN_CSS(cssFile, true);
}
#endif
#endif // if defined(EMBED_ESPEASY_DEFAULT_MIN_CSS) || defined(WEBSERVER_EMBED_CUSTOM_CSS)
}
void serve_favicon() {
@@ -130,163 +135,177 @@ void serve_favicon() {
addHtml(F("'/>"));
/*
addHtml(F("<link"));
addHtmlAttribute(F("rel"), F("icon"));
addHtmlAttribute(F("type"), F("image/x-icon"));
addHtmlAttribute(F("href"), generate_external_URL(F("favicon.ico"), true));
addHtml('/', '>');
*/
#endif
addHtml(F("<link"));
addHtmlAttribute(F("rel"), F("icon"));
addHtmlAttribute(F("type"), F("image/x-icon"));
addHtmlAttribute(F("href"), generate_external_URL(F("favicon.ico"), true));
addHtml('/', '>');
*/
#endif // ifdef WEBSERVER_FAVICON_CDN
#ifndef LIMIT_BUILD_SIZE
addHtml(F("<link"));
addHtmlAttribute(F("rel"), F("icon"));
addHtmlAttribute(F("rel"), F("icon"));
addHtmlAttribute(F("type"), F("image/svg+xml"));
addHtmlAttribute(F("href"), F("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='113.392' height='113.392' viewBox='0 0 30.002 30.002'%3E%3Cpath fill='%23f9f9f9' d='M0 24.728V5.272A5.272 5.272 0 0 1 5.272 0h19.456c2.91 0 5.274 2.36 5.274 5.272v19.456a5.276 5.276 0 0 1-5.274 5.274H5.272A5.274 5.274 0 0 1 0 24.728zM30.002 0'/%3E%3Cpath fill='%2307d' stroke='%2307d' stroke-linecap='round' stroke-width='2.636' d='m3.75 11.25 7.5-7.5M3.75 18.75l15-15M3.75 26.25l22.5-22.5M11.25 26.25l15-15'/%3E%3Cpath fill='%2307d' d='M27.374 24.377a2.999 2.999 0 1 0-5.999 0 2.999 2.999 0 0 0 3.002 2.997 2.997 2.997 0 0 0 2.997-2.997zm-2.997 0'/%3E%3C/svg%3E"));
addHtmlAttribute(F("href"),
F(
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='113.392' height='113.392' viewBox='0 0 30.002 30.002'%3E%3Cpath fill='%23f9f9f9' d='M0 24.728V5.272A5.272 5.272 0 0 1 5.272 0h19.456c2.91 0 5.274 2.36 5.274 5.272v19.456a5.276 5.276 0 0 1-5.274 5.274H5.272A5.274 5.274 0 0 1 0 24.728zM30.002 0'/%3E%3Cpath fill='%2307d' stroke='%2307d' stroke-linecap='round' stroke-width='2.636' d='m3.75 11.25 7.5-7.5M3.75 18.75l15-15M3.75 26.25l22.5-22.5M11.25 26.25l15-15'/%3E%3Cpath fill='%2307d' d='M27.374 24.377a2.999 2.999 0 1 0-5.999 0 2.999 2.999 0 0 0 3.002 2.997 2.997 2.997 0 0 0 2.997-2.997zm-2.997 0'/%3E%3C/svg%3E"));
addHtml('/', '>');
/*
<link rel="icon" type="image/svg+xml"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='113.392' height='113.392' viewBox='0 0 30.002 30.002'%3E%3Cpath fill='%23f9f9f9' d='M0 24.728V5.272A5.272 5.272 0 0 1 5.272 0h19.456c2.91 0 5.274 2.36 5.274 5.272v19.456a5.276 5.276 0 0 1-5.274 5.274H5.272A5.274 5.274 0 0 1 0 24.728zM30.002 0'/%3E%3Cpath fill='%2307d' stroke='%2307d' stroke-linecap='round' stroke-width='2.636' d='m3.75 11.25 7.5-7.5M3.75 18.75l15-15M3.75 26.25l22.5-22.5M11.25 26.25l15-15'/%3E%3Cpath fill='%2307d' d='M27.374 24.377a2.999 2.999 0 1 0-5.999 0 2.999 2.999 0 0 0 3.002 2.997 2.997 2.997 0 0 0 2.997-2.997zm-2.997 0'/%3E%3C/svg%3E" />
*/
#endif
/*
<link rel="icon" type="image/svg+xml"
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='113.392' height='113.392' viewBox='0 0 30.002
30.002'%3E%3Cpath fill='%23f9f9f9' d='M0 24.728V5.272A5.272 5.272 0 0 1 5.272 0h19.456c2.91 0 5.274 2.36 5.274 5.272v19.456a5.276
5.276 0 0 1-5.274 5.274H5.272A5.274 5.274 0 0 1 0 24.728zM30.002 0'/%3E%3Cpath fill='%2307d' stroke='%2307d'
stroke-linecap='round' stroke-width='2.636' d='m3.75 11.25 7.5-7.5M3.75 18.75l15-15M3.75 26.25l22.5-22.5M11.25
26.25l15-15'/%3E%3Cpath fill='%2307d' d='M27.374 24.377a2.999 2.999 0 1 0-5.999 0 2.999 2.999 0 0 0 3.002 2.997 2.997 2.997 0 0 0
2.997-2.997zm-2.997 0'/%3E%3C/svg%3E" />
*/
#endif // ifndef LIMIT_BUILD_SIZE
}
void serve_JS(JSfiles_e JSfile) {
const __FlashStringHelper * url = F("");
const __FlashStringHelper * id = F("");
bool useDefer = true;
const __FlashStringHelper *url = F("");
const __FlashStringHelper *id = F("");
bool useDefer = true;
#if defined(WEBSERVER_INCLUDE_JS)
bool useCDN = false;
bool useCDN = false;
#endif
switch (JSfile) {
switch (JSfile)
{
case JSfiles_e::UpdateSensorValuesDevicePage:
url = F("update_sensor_values_device_page.js");
break;
case JSfiles_e::FetchAndParseLog:
url = F("fetch_and_parse_log.js");
break;
case JSfiles_e::SaveRulesFile:
url = F("rules_save.js");
break;
case JSfiles_e::GitHubClipboard:
url = F("github_clipboard.js");
break;
case JSfiles_e::Reboot:
url = F("reboot.js");
break;
case JSfiles_e::Toasting:
url = F("toasting.js");
break;
case JSfiles_e::SplitPasteInput:
url = F("split_paste.js");
break;
#if FEATURE_RULES_EASY_COLOR_CODE
case JSfiles_e::EasyColorCode_codemirror:
url = F("codemirror.min.js");
useDefer = false;
# if defined(WEBSERVER_INCLUDE_JS)
useCDN = true;
# endif
break;
case JSfiles_e::EasyColorCode_espeasy:
url = F("espeasy.min.js");
useDefer = false;
# if defined(WEBSERVER_INCLUDE_JS)
useCDN = true;
# endif
break;
case JSfiles_e::EasyColorCode_cm_plugins:
url = F("cm-plugins.min.js");
id = F("id='anyword'");
useDefer = false;
# if defined(WEBSERVER_INCLUDE_JS)
useCDN = true;
# endif
break;
#endif // if FEATURE_RULES_EASY_COLOR_CODE
#ifdef USES_P113
case JSfiles_e::P113_script:
url = F("p113_script.js");
break;
#endif // ifdef USES_P113
#ifdef USES_P165
case JSfiles_e::P165_digit:
url = F("p165_digit.js");
break;
#endif // ifdef USES_P165
}
// Work-around for shortening the filename when stored on SPIFFS file system
// Files cannot be longer than 31 characters
const __FlashStringHelper *fname =
(JSfile == JSfiles_e::UpdateSensorValuesDevicePage) ?
F("upd_values_device_page.js") : url;
if (!fileExists(fname))
{
#if defined(WEBSERVER_INCLUDE_JS)
if (!useCDN) {
html_add_script_arg(id, useDefer);
switch (JSfile)
{
case JSfiles_e::UpdateSensorValuesDevicePage:
url = F("update_sensor_values_device_page.js");
# ifdef WEBSERVER_DEVICES
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS));
# endif
break;
case JSfiles_e::FetchAndParseLog:
url = F("fetch_and_parse_log.js");
# ifdef WEBSERVER_LOG
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_FETCH_AND_PARSE_LOG_JS));
# endif
break;
case JSfiles_e::SaveRulesFile:
url = F("rules_save.js");
# ifdef WEBSERVER_RULES
TXBuffer.addFlashString((PGM_P)FPSTR(jsSaveRules));
# endif
break;
case JSfiles_e::GitHubClipboard:
url = F("github_clipboard.js");
# ifdef WEBSERVER_GITHUB_COPY
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_GITHUB_CLIPBOARD_JS));
# endif
break;
case JSfiles_e::Reboot:
url = F("reboot.js");
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_REBOOT_JS));
break;
case JSfiles_e::Toasting:
url = F("toasting.js");
TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageBegin));
// we can push custom messages here in future releases...
addHtml(F("Submitted"));
TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageEnd));
break;
case JSfiles_e::SplitPasteInput:
url = F("split_paste.js");
TXBuffer.addFlashString((PGM_P)FPSTR(jsSplitMultipleFields));
// After this, make sure to call it, like this:
// split('$', ".query-input")
break;
#if FEATURE_RULES_EASY_COLOR_CODE
# if FEATURE_RULES_EASY_COLOR_CODE
case JSfiles_e::EasyColorCode_codemirror:
url = F("codemirror.min.js");
useDefer = false;
#if defined(WEBSERVER_INCLUDE_JS)
useCDN = true;
#endif
break;
case JSfiles_e::EasyColorCode_espeasy:
url = F("espeasy.min.js");
useDefer = false;
#if defined(WEBSERVER_INCLUDE_JS)
useCDN = true;
#endif
break;
case JSfiles_e::EasyColorCode_cm_plugins:
url = F("cm-plugins.min.js");
id = F("id='anyword'");
useDefer = false;
#if defined(WEBSERVER_INCLUDE_JS)
useCDN = true;
#endif
break;
#endif
#ifdef USES_P113
# endif // if FEATURE_RULES_EASY_COLOR_CODE
# ifdef USES_P113
case JSfiles_e::P113_script:
url = F("p113_script.js");
TXBuffer.addFlashString((PGM_P)FPSTR(p113_script));
break;
#endif // ifdef USES_P113
#ifdef USES_P165
# endif // ifdef USES_P113
# ifdef USES_P165
case JSfiles_e::P165_digit:
url = F("p165_digit.js");
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_P165_DIGIT_JS));
break;
#endif // ifdef USES_P165
}
// Work-around for shortening the filename when stored on SPIFFS file system
// Files cannot be longer than 31 characters
const __FlashStringHelper * fname =
(JSfile == JSfiles_e::UpdateSensorValuesDevicePage) ?
F("upd_values_device_page.js") : url;
if (!fileExists(fname))
{
#if defined(WEBSERVER_INCLUDE_JS)
if (!useCDN) {
html_add_script_arg(id, useDefer);
switch (JSfile) {
case JSfiles_e::UpdateSensorValuesDevicePage:
#ifdef WEBSERVER_DEVICES
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS));
#endif
break;
case JSfiles_e::FetchAndParseLog:
#ifdef WEBSERVER_LOG
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_FETCH_AND_PARSE_LOG_JS));
#endif
break;
case JSfiles_e::SaveRulesFile:
#ifdef WEBSERVER_RULES
TXBuffer.addFlashString((PGM_P)FPSTR(jsSaveRules));
#endif
break;
case JSfiles_e::GitHubClipboard:
#ifdef WEBSERVER_GITHUB_COPY
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_GITHUB_CLIPBOARD_JS));
#endif
break;
case JSfiles_e::Reboot:
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_REBOOT_JS));
break;
case JSfiles_e::Toasting:
TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageBegin));
// we can push custom messages here in future releases...
addHtml(F("Submitted"));
TXBuffer.addFlashString((PGM_P)FPSTR(jsToastMessageEnd));
break;
case JSfiles_e::SplitPasteInput:
TXBuffer.addFlashString((PGM_P)FPSTR(jsSplitMultipleFields));
// After this, make sure to call it, like this:
// split('$', ".query-input")
break;
#if FEATURE_RULES_EASY_COLOR_CODE
case JSfiles_e::EasyColorCode_codemirror:
case JSfiles_e::EasyColorCode_espeasy:
case JSfiles_e::EasyColorCode_cm_plugins:
break;
#endif
#ifdef USES_P113
case JSfiles_e::P113_script:
TXBuffer.addFlashString((PGM_P)FPSTR(p113_script));
break;
#endif // ifdef USES_P113
#ifdef USES_P165
case JSfiles_e::P165_digit:
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_P165_DIGIT_JS));
break;
#endif // ifdef USES_P165
}
html_add_script_end();
return;
}
#endif
serve_CDN_JS(url, id, useDefer);
} else {
serve_CDN_JS(fname, id, useDefer);
# endif // ifdef USES_P165
}
html_add_script_end();
return;
}
#endif // if defined(WEBSERVER_INCLUDE_JS)
serve_CDN_JS(url, id, useDefer);
} else {
serve_CDN_JS(fname, id, useDefer);
}
}
-2
View File
@@ -7,8 +7,6 @@
//-V::569
String generate_external_URL(const String& fname);
void serve_favicon();
enum class JSfiles_e {
+108 -104
View File
@@ -32,6 +32,114 @@ void setLogLevelFor(LogDestination destination, LabelType::Enum label) {
setLogLevelFor(destination, getFormItemInt(getInternalLabel(label)));
}
static void addFormDstSelect(bool isStart, uint16_t choice) {
uint16_t tmpstart(choice);
uint16_t tmpend(choice);
if (!TimeChangeRule(choice, 0).isValid()) {
time_zone.getDefaultDst_flash_values(tmpstart, tmpend);
}
TimeChangeRule rule(isStart ? tmpstart : tmpend, 0);
{
const __FlashStringHelper * week[] = { F("Last"), F("1st"), F("2nd"), F("3rd"), F("4th") };
constexpr int weekValues[] = { 0, 1, 2, 3, 4 };
addRowLabel(concat(
isStart ? F("Start") : F("End"),
F(" (week, dow, month)")));
const FormSelectorOptions selector(NR_ELEMENTS(weekValues), week, weekValues);
selector.addSelector(
isStart ? F("dststartweek") : F("dstendweek"),
rule.week);
}
html_BR();
{
const __FlashStringHelper * dow[] = { F("Sun"), F("Mon"), F("Tue"), F("Wed"), F("Thu"), F("Fri"), F("Sat") };
constexpr int dowValues[] = { 1, 2, 3, 4, 5, 6, 7 };
const FormSelectorOptions selector(NR_ELEMENTS(dowValues), dow, dowValues);
selector.addSelector(
isStart ? F("dststartdow") : F("dstenddow"),
rule.dow);
}
html_BR();
{
const __FlashStringHelper * month[] = { F("Jan"), F("Feb"), F("Mar"), F("Apr"), F("May"), F("Jun"), F("Jul"), F("Aug"), F("Sep"), F("Oct"), F("Nov"), F(
"Dec") };
constexpr int monthValues[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
const FormSelectorOptions selector(NR_ELEMENTS(monthValues), month, monthValues);
selector.addSelector(
isStart ? F("dststartmonth") : F("dstendmonth"),
rule.month);
}
addFormNumericBox(
isStart ? F("Start (localtime, e.g. 2h&rarr;3h)") : F("End (localtime, e.g. 3h&rarr;2h)"),
isStart ? F("dststarthour") : F("dstendhour"),
rule.hour, 0, 23);
addUnit(isStart ? F("hour &#x21b7;") : F("hour &#x21b6;"));
}
#if FEATURE_EXT_RTC
static void addFormExtTimeSourceSelect(const __FlashStringHelper * label, const __FlashStringHelper * id, ExtTimeSource_e choice)
{
addRowLabel(label);
const __FlashStringHelper * options[] = {
F("None"),
toString(ExtTimeSource_e::DS1307),
toString(ExtTimeSource_e::DS3231),
toString(ExtTimeSource_e::DS3232),
toString(ExtTimeSource_e::PCF8523),
toString(ExtTimeSource_e::PCF8563),
#if FEATURE_EXT_RTC_PCF8583
toString(ExtTimeSource_e::PCF8583),
toString(ExtTimeSource_e::PCF8583a),
#endif // if FEATURE_EXT_RTC_PCF8583
};
constexpr int optionValues[] = {
static_cast<int>(ExtTimeSource_e::None),
static_cast<int>(ExtTimeSource_e::DS1307),
static_cast<int>(ExtTimeSource_e::DS3231),
static_cast<int>(ExtTimeSource_e::DS3232),
static_cast<int>(ExtTimeSource_e::PCF8523),
static_cast<int>(ExtTimeSource_e::PCF8563),
#if FEATURE_EXT_RTC_PCF8583
static_cast<int>(ExtTimeSource_e::PCF8583),
static_cast<int>(ExtTimeSource_e::PCF8583a),
#endif // if FEATURE_EXT_RTC_PCF8583
};
const FormSelectorOptions selector(NR_ELEMENTS(optionValues), options, optionValues);
selector.addSelector(id, static_cast<int>(choice));
}
#endif
static void addFormLogLevelSelect(LabelType::Enum label, int choice)
{
#ifdef BUILD_NO_DEBUG
if (choice > LOG_LEVEL_INFO) choice = LOG_LEVEL_INFO;
#endif
addRowLabel(getLabel(label));
addLogLevelFormSelectorOptions(getInternalLabel(label), choice);
}
#if FEATURE_SYSLOG
static void addFormLogFacilitySelect(const __FlashStringHelper * label, const __FlashStringHelper * id, int choice)
{
addRowLabel(label);
const __FlashStringHelper * options[] =
{ F("Kernel"), F("User"), F("Daemon"), F("Message"), F("Local0"), F("Local1"),
F("Local2"), F("Local3"), F("Local4"), F("Local5"), F("Local6"), F("Local7") };
const int optionValues[] = { 0, 1, 3, 5, 16, 17, 18, 19, 20, 21, 22, 23 };
const FormSelectorOptions selector(NR_ELEMENTS(options), options, optionValues);
selector.addSelector(id, choice);
}
#endif
// ********************************************************************************
// Web Interface config page
// ********************************************************************************
@@ -419,110 +527,6 @@ void handle_advanced() {
sendTail_stdtemplate();
}
void addFormDstSelect(bool isStart, uint16_t choice) {
uint16_t tmpstart(choice);
uint16_t tmpend(choice);
if (!TimeChangeRule(choice, 0).isValid()) {
time_zone.getDefaultDst_flash_values(tmpstart, tmpend);
}
TimeChangeRule rule(isStart ? tmpstart : tmpend, 0);
{
const __FlashStringHelper * week[] = { F("Last"), F("1st"), F("2nd"), F("3rd"), F("4th") };
constexpr int weekValues[] = { 0, 1, 2, 3, 4 };
addRowLabel(concat(
isStart ? F("Start") : F("End"),
F(" (week, dow, month)")));
const FormSelectorOptions selector(NR_ELEMENTS(weekValues), week, weekValues);
selector.addSelector(
isStart ? F("dststartweek") : F("dstendweek"),
rule.week);
}
html_BR();
{
const __FlashStringHelper * dow[] = { F("Sun"), F("Mon"), F("Tue"), F("Wed"), F("Thu"), F("Fri"), F("Sat") };
constexpr int dowValues[] = { 1, 2, 3, 4, 5, 6, 7 };
const FormSelectorOptions selector(NR_ELEMENTS(dowValues), dow, dowValues);
selector.addSelector(
isStart ? F("dststartdow") : F("dstenddow"),
rule.dow);
}
html_BR();
{
const __FlashStringHelper * month[] = { F("Jan"), F("Feb"), F("Mar"), F("Apr"), F("May"), F("Jun"), F("Jul"), F("Aug"), F("Sep"), F("Oct"), F("Nov"), F(
"Dec") };
constexpr int monthValues[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
const FormSelectorOptions selector(NR_ELEMENTS(monthValues), month, monthValues);
selector.addSelector(
isStart ? F("dststartmonth") : F("dstendmonth"),
rule.month);
}
addFormNumericBox(
isStart ? F("Start (localtime, e.g. 2h&rarr;3h)") : F("End (localtime, e.g. 3h&rarr;2h)"),
isStart ? F("dststarthour") : F("dstendhour"),
rule.hour, 0, 23);
addUnit(isStart ? F("hour &#x21b7;") : F("hour &#x21b6;"));
}
void addFormExtTimeSourceSelect(const __FlashStringHelper * label, const __FlashStringHelper * id, ExtTimeSource_e choice)
{
addRowLabel(label);
const __FlashStringHelper * options[] = {
F("None"),
toString(ExtTimeSource_e::DS1307),
toString(ExtTimeSource_e::DS3231),
toString(ExtTimeSource_e::DS3232),
toString(ExtTimeSource_e::PCF8523),
toString(ExtTimeSource_e::PCF8563),
#if FEATURE_EXT_RTC_PCF8583
toString(ExtTimeSource_e::PCF8583),
toString(ExtTimeSource_e::PCF8583a),
#endif // if FEATURE_EXT_RTC_PCF8583
};
constexpr int optionValues[] = {
static_cast<int>(ExtTimeSource_e::None),
static_cast<int>(ExtTimeSource_e::DS1307),
static_cast<int>(ExtTimeSource_e::DS3231),
static_cast<int>(ExtTimeSource_e::DS3232),
static_cast<int>(ExtTimeSource_e::PCF8523),
static_cast<int>(ExtTimeSource_e::PCF8563),
#if FEATURE_EXT_RTC_PCF8583
static_cast<int>(ExtTimeSource_e::PCF8583),
static_cast<int>(ExtTimeSource_e::PCF8583a),
#endif // if FEATURE_EXT_RTC_PCF8583
};
const FormSelectorOptions selector(NR_ELEMENTS(optionValues), options, optionValues);
selector.addSelector(id, static_cast<int>(choice));
}
void addFormLogLevelSelect(LabelType::Enum label, int choice)
{
#ifdef BUILD_NO_DEBUG
if (choice > LOG_LEVEL_INFO) choice = LOG_LEVEL_INFO;
#endif
addRowLabel(getLabel(label));
addLogLevelFormSelectorOptions(getInternalLabel(label), choice);
}
#if FEATURE_SYSLOG
void addFormLogFacilitySelect(const __FlashStringHelper * label, const __FlashStringHelper * id, int choice)
{
addRowLabel(label);
const __FlashStringHelper * options[] =
{ F("Kernel"), F("User"), F("Daemon"), F("Message"), F("Local0"), F("Local1"),
F("Local2"), F("Local3"), F("Local4"), F("Local5"), F("Local6"), F("Local7") };
const int optionValues[] = { 0, 1, 3, 5, 16, 17, 18, 19, 20, 21, 22, 23 };
const FormSelectorOptions selector(NR_ELEMENTS(options), options, optionValues);
selector.addSelector(id, choice);
}
#endif
#endif // ifdef WEBSERVER_ADVANCED
-15
View File
@@ -13,20 +13,5 @@
// ********************************************************************************
void handle_advanced();
void addFormDstSelect(bool isStart, uint16_t choice);
void addFormExtTimeSourceSelect(const __FlashStringHelper * label, const __FlashStringHelper * id, ExtTimeSource_e choice);
void addFormLogLevelSelect(LabelType::Enum label, int choice);
#if FEATURE_SYSLOG
void addFormLogFacilitySelect(const __FlashStringHelper * label, const __FlashStringHelper * id, int choice);
#endif
#endif // ifdef WEBSERVER_ADVANCED
#endif
+52 -50
View File
@@ -7,7 +7,7 @@
# include "../WebServer/HTML_wrappers.h"
# include "../WebServer/JSON.h"
void add_ChartJS_array(KeyValueWriter& parent,
static void add_ChartJS_array(KeyValueWriter& parent,
int valueCount,
const String array[])
{
@@ -16,7 +16,7 @@ void add_ChartJS_array(KeyValueWriter& parent,
}
}
void add_ChartJS_array(KeyValueWriter& parent,
static void add_ChartJS_array(KeyValueWriter& parent,
int valueCount,
const float array[],
uint8_t nrDecimals)
@@ -26,7 +26,7 @@ void add_ChartJS_array(KeyValueWriter& parent,
}
}
void add_ChartJS_array(KeyValueWriter& parent,
static void add_ChartJS_array(KeyValueWriter& parent,
int valueCount,
const int array[])
{
@@ -54,53 +54,7 @@ UP_KeyValueWriter add_ChartJS_chart_header(
onlyJSON);
}
UP_KeyValueWriter add_ChartJS_chart_header(
const __FlashStringHelper *chartType,
const String & id,
const ChartJS_title & chartTitle,
ChartJS_options_scales & options,
bool enableZoom,
size_t nrSamples,
bool onlyJSON)
{
if (!onlyJSON) {
addHtml(F("<div class=\"chart-container\" style=\"position: relative; height:40vh; width:95vw\">"));
addHtml(F("<canvas"));
addHtmlAttribute(F("id"), id);
addHtml(F("></canvas>"));
addHtml(F("</div>"));
const char *id_c_str = id.c_str();
addHtml(strformat(
F("<script>"
"const %sc=document.getElementById('%s');"
"const my_%s_C=new Chart(%sc,\n"),
id_c_str,
id_c_str,
id_c_str,
id_c_str));
}
UP_KeyValueWriter_JSON chartJSON(new (std::nothrow) KeyValueWriter_JSON(true));
if (chartJSON) {
chartJSON->allowFormatOverrides(false);
if (!onlyJSON) {
chartJSON->setFooter(F("\n);</script>"));
}
add_ChartJS_chart_JSON_header(
*chartJSON,
chartType,
chartTitle,
options,
nrSamples,
enableZoom);
}
return std::move(chartJSON);
}
void add_ChartJS_chart_JSON_header(
static void add_ChartJS_chart_JSON_header(
KeyValueWriter_JSON & parent,
const __FlashStringHelper *chartType,
const ChartJS_title & chartTitle,
@@ -161,6 +115,54 @@ void add_ChartJS_chart_JSON_header(
}
}
UP_KeyValueWriter add_ChartJS_chart_header(
const __FlashStringHelper *chartType,
const String & id,
const ChartJS_title & chartTitle,
ChartJS_options_scales & options,
bool enableZoom,
size_t nrSamples,
bool onlyJSON)
{
if (!onlyJSON) {
addHtml(F("<div class=\"chart-container\" style=\"position: relative; height:40vh; width:95vw\">"));
addHtml(F("<canvas"));
addHtmlAttribute(F("id"), id);
addHtml(F("></canvas>"));
addHtml(F("</div>"));
const char *id_c_str = id.c_str();
addHtml(strformat(
F("<script>"
"const %sc=document.getElementById('%s');"
"const my_%s_C=new Chart(%sc,\n"),
id_c_str,
id_c_str,
id_c_str,
id_c_str));
}
UP_KeyValueWriter_JSON chartJSON(new (std::nothrow) KeyValueWriter_JSON(true));
if (chartJSON) {
chartJSON->allowFormatOverrides(false);
if (!onlyJSON) {
chartJSON->setFooter(F("\n);</script>"));
}
add_ChartJS_chart_JSON_header(
*chartJSON,
chartType,
chartTitle,
options,
nrSamples,
enableZoom);
}
return std::move(chartJSON);
}
void add_ChartJS_chart_labels(
KeyValueWriter& parent,
int valueCount,
-8
View File
@@ -67,14 +67,6 @@ UP_KeyValueWriter add_ChartJS_chart_header(
size_t nrSamples = 0,
bool onlyJSON = false);
void add_ChartJS_chart_JSON_header(
KeyValueWriter_JSON & parent,
const __FlashStringHelper *chartType,
const ChartJS_title & chartTitle,
ChartJS_options_scales & options,
size_t nrSamples,
bool enableZoom
);
void add_ChartJS_chart_labels(
KeyValueWriter& parent,
+118 -113
View File
@@ -28,119 +28,11 @@
# include "../Helpers/_CPlugin_Helper_webform.h"
# include "../Helpers/ESPEasy_Storage.h"
// ********************************************************************************
// Web Interface controller page
// ********************************************************************************
void handle_controllers() {
# ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("handle_controllers"));
# endif // ifndef BUILD_NO_RAM_TRACKER
if (!startStream_send_stdTemplate(MENU_INDEX_CONTROLLERS)) { return; }
// 'index' value in the URL
uint8_t controllerindex = getFormItemInt(F("index"), 0);
const bool controllerIndexSet = controllerindex != 0 && validControllerIndex(controllerindex - 1);
--controllerindex; // Index in URL is starting from 1, but starting from 0 in the array.
const int protocol_webarg_value = getFormItemInt(F("protocol"), -1);
// submitted data
if ((protocol_webarg_value != -1) && controllerIndexSet)
{
const protocolIndex_t protocolIndex = protocol_webarg_value;
bool mustInit = false;
bool mustCallCpluginSave = false;
{
// Place in a scope to free ControllerSettings memory ASAP
MakeControllerSettings(ControllerSettings); // -V522
if (!AllocatedControllerSettings()) {
addHtmlError(F("Not enough free memory to save settings"));
} else {
// Need to make sure every byte between the members is also zero
// Otherwise the checksum will fail and settings will be saved too often.
ControllerSettings->reset();
if (Settings.Protocol[controllerindex] != protocolIndex)
{
// Protocol has changed.
Settings.Protocol[controllerindex] = protocolIndex;
// there is a protocolIndex selected?
if (protocolIndex != 0)
{
mustInit = true;
handle_controllers_clearLoadDefaults(controllerindex, *ControllerSettings);
}
}
// subitted same protocolIndex
else
{
// there is a protocolIndex selected
if (protocolIndex != 0)
{
mustInit = true;
handle_controllers_CopySubmittedSettings(controllerindex, *ControllerSettings);
mustCallCpluginSave = true;
}
}
addHtmlError(SaveControllerSettings(controllerindex, *ControllerSettings));
# if FEATURE_MQTT_DISCOVER
// AutoDiscovery enabled?
if (ControllerSettings->mqtt_autoDiscovery()
&& Settings.ControllerEnabled[controllerindex]
// && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != 0)
&& (ControllerSettings->MqttAutoDiscoveryTopic[0] != 0)
) {
// Generate random time-offset in 0.1 sec, range 1..30 seconds
mqttDiscoveryTimeout = random(10, MQTT_DISCOVERY_MAX_DELAY_0_1_SECONDS);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Start AutoDiscovery on Save. Starting in %.1f sec."), mqttDiscoveryTimeout / 10));
#else // ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery starting in %.1f sec."), mqttDiscoveryTimeout / 10));
#endif // ifndef BUILD_NO_DEBUG
}
}
# endif // if FEATURE_MQTT_DISCOVER
}
}
if (mustCallCpluginSave) {
// Call CPLUGIN_WEBFORM_SAVE after destructing ControllerSettings object to reduce RAM usage.
// Controller plugin almost only deals with custom controller settings.
// Even if they need to save things to the ControllerSettings, then the changes must
// already be saved first as the CPluginCall does not have the ControllerSettings as argument.
handle_controllers_CopySubmittedSettings_CPluginCall(controllerindex);
}
addHtmlError(SaveSettings());
if (mustInit) {
// Init controller plugin using the new settings.
CPlugin_Exit_Init(controllerindex);
}
}
if (controllerIndexSet)
{
handle_controllers_ControllerSettingsPage(controllerindex);
} else {
handle_controllers_ShowAllControllersTable();
}
sendTail_stdtemplate();
}
// ********************************************************************************
// Selected controller has changed.
// Clear all Controller settings and load some defaults
// ********************************************************************************
void handle_controllers_clearLoadDefaults(uint8_t controllerindex, ControllerSettingsStruct& ControllerSettings)
static void handle_controllers_clearLoadDefaults(uint8_t controllerindex, ControllerSettingsStruct& ControllerSettings)
{
// Protocol has changed and it was not an empty one.
// reset (some) default-settings
@@ -185,10 +77,12 @@ void handle_controllers_clearLoadDefaults(uint8_t controllerindex, ControllerSet
ClearCustomControllerSettings(controllerindex);
}
// ********************************************************************************
// Collect all submitted form data and store in the ControllerSettings
// ********************************************************************************
void handle_controllers_CopySubmittedSettings(uint8_t controllerindex, ControllerSettingsStruct& ControllerSettings)
static void handle_controllers_CopySubmittedSettings(uint8_t controllerindex, ControllerSettingsStruct& ControllerSettings)
{
// copy all settings to controller settings struct
for (int parameterIdx = 0; parameterIdx <= ControllerSettingsStruct::CONTROLLER_ENABLED; ++parameterIdx) {
@@ -197,7 +91,7 @@ void handle_controllers_CopySubmittedSettings(uint8_t controllerindex, Controlle
}
}
void handle_controllers_CopySubmittedSettings_CPluginCall(uint8_t controllerindex) {
static void handle_controllers_CopySubmittedSettings_CPluginCall(uint8_t controllerindex) {
protocolIndex_t ProtocolIndex = getProtocolIndex_from_ControllerIndex(controllerindex);
if (validProtocolIndex(ProtocolIndex)) {
@@ -213,7 +107,7 @@ void handle_controllers_CopySubmittedSettings_CPluginCall(uint8_t controllerinde
// ********************************************************************************
// Show table with all selected controllers
// ********************************************************************************
void handle_controllers_ShowAllControllersTable()
static void handle_controllers_ShowAllControllersTable()
{
html_add_form();
html_table_class_multirow();
@@ -278,7 +172,7 @@ void handle_controllers_ShowAllControllersTable()
// ********************************************************************************
// Show the controller settings page
// ********************************************************************************
void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex)
static void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex)
{
if (!validControllerIndex(controllerindex)) {
return;
@@ -726,4 +620,115 @@ void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex
html_end_form();
}
// ********************************************************************************
// Web Interface controller page
// ********************************************************************************
void handle_controllers() {
# ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("handle_controllers"));
# endif // ifndef BUILD_NO_RAM_TRACKER
if (!startStream_send_stdTemplate(MENU_INDEX_CONTROLLERS)) { return; }
// 'index' value in the URL
uint8_t controllerindex = getFormItemInt(F("index"), 0);
const bool controllerIndexSet = controllerindex != 0 && validControllerIndex(controllerindex - 1);
--controllerindex; // Index in URL is starting from 1, but starting from 0 in the array.
const int protocol_webarg_value = getFormItemInt(F("protocol"), -1);
// submitted data
if ((protocol_webarg_value != -1) && controllerIndexSet)
{
const protocolIndex_t protocolIndex = protocol_webarg_value;
bool mustInit = false;
bool mustCallCpluginSave = false;
{
// Place in a scope to free ControllerSettings memory ASAP
MakeControllerSettings(ControllerSettings); // -V522
if (!AllocatedControllerSettings()) {
addHtmlError(F("Not enough free memory to save settings"));
} else {
// Need to make sure every byte between the members is also zero
// Otherwise the checksum will fail and settings will be saved too often.
ControllerSettings->reset();
if (Settings.Protocol[controllerindex] != protocolIndex)
{
// Protocol has changed.
Settings.Protocol[controllerindex] = protocolIndex;
// there is a protocolIndex selected?
if (protocolIndex != 0)
{
mustInit = true;
handle_controllers_clearLoadDefaults(controllerindex, *ControllerSettings);
}
}
// subitted same protocolIndex
else
{
// there is a protocolIndex selected
if (protocolIndex != 0)
{
mustInit = true;
handle_controllers_CopySubmittedSettings(controllerindex, *ControllerSettings);
mustCallCpluginSave = true;
}
}
addHtmlError(SaveControllerSettings(controllerindex, *ControllerSettings));
# if FEATURE_MQTT_DISCOVER
// AutoDiscovery enabled?
if (ControllerSettings->mqtt_autoDiscovery()
&& Settings.ControllerEnabled[controllerindex]
// && (ControllerSettings->MqttAutoDiscoveryTrigger[0] != 0)
&& (ControllerSettings->MqttAutoDiscoveryTopic[0] != 0)
) {
// Generate random time-offset in 0.1 sec, range 1..30 seconds
mqttDiscoveryTimeout = random(10, MQTT_DISCOVERY_MAX_DELAY_0_1_SECONDS);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Start AutoDiscovery on Save. Starting in %.1f sec."), mqttDiscoveryTimeout / 10));
#else // ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_INFO, strformat(F("MQTT : Discovery starting in %.1f sec."), mqttDiscoveryTimeout / 10));
#endif // ifndef BUILD_NO_DEBUG
}
}
# endif // if FEATURE_MQTT_DISCOVER
}
}
if (mustCallCpluginSave) {
// Call CPLUGIN_WEBFORM_SAVE after destructing ControllerSettings object to reduce RAM usage.
// Controller plugin almost only deals with custom controller settings.
// Even if they need to save things to the ControllerSettings, then the changes must
// already be saved first as the CPluginCall does not have the ControllerSettings as argument.
handle_controllers_CopySubmittedSettings_CPluginCall(controllerindex);
}
addHtmlError(SaveSettings());
if (mustInit) {
// Init controller plugin using the new settings.
CPlugin_Exit_Init(controllerindex);
}
}
if (controllerIndexSet)
{
handle_controllers_ControllerSettingsPage(controllerindex);
} else {
handle_controllers_ShowAllControllersTable();
}
sendTail_stdtemplate();
}
#endif // ifdef WEBSERVER_CONTROLLERS
-26
View File
@@ -14,32 +14,6 @@
// ********************************************************************************
void handle_controllers();
// ********************************************************************************
// Selected controller has changed.
// Clear all Controller settings and load some defaults
// ********************************************************************************
void handle_controllers_clearLoadDefaults(uint8_t controllerindex, ControllerSettingsStruct& ControllerSettings);
// ********************************************************************************
// Collect all submitted form data and store in the ControllerSettings
// ********************************************************************************
void handle_controllers_CopySubmittedSettings(uint8_t controllerindex, ControllerSettingsStruct& ControllerSettings);
void handle_controllers_CopySubmittedSettings_CPluginCall(uint8_t controllerindex);
// ********************************************************************************
// Show table with all selected controllers
// ********************************************************************************
void handle_controllers_ShowAllControllersTable();
// ********************************************************************************
// Show the controller settings page
// ********************************************************************************
void handle_controllers_ControllerSettingsPage(controllerIndex_t controllerindex);
#endif // ifdef WEBSERVER_CONTROLLERS
#endif
File diff suppressed because it is too large. Load diff
+11 -80
View File
@@ -1,97 +1,28 @@
#ifndef WEBSERVER_WEBSERVER_DEVICESPAGE_H
#define WEBSERVER_WEBSERVER_DEVICESPAGE_H
#pragma once
#include "../WebServer/common.h"
#ifdef WEBSERVER_DEVICES
#include "../DataTypes/DeviceIndex.h"
#include "../DataTypes/TaskIndex.h"
#include "../DataTypes/PluginID.h"
# include "../DataTypes/DeviceIndex.h"
# include "../DataTypes/TaskIndex.h"
# include "../DataTypes/PluginID.h"
void handle_devices();
// ********************************************************************************
// Add a device select dropdown list
// TODO TD-er: Add JavaScript filter:
// https://www.w3schools.com/howto/howto_js_filter_dropdown.asp
// ********************************************************************************
void addDeviceSelect(const __FlashStringHelper * name, pluginID_t choice);
// ********************************************************************************
// Collect all submitted form data and store the task settings
// ********************************************************************************
void handle_devices_CopySubmittedSettings(taskIndex_t taskIndex, pluginID_t taskdevicenumber);
// ********************************************************************************
// Show table with all selected Tasks/Devices
// ********************************************************************************
void handle_devicess_ShowAllTasksTable(uint8_t page);
#if FEATURE_ESPEASY_P2P
void format_originating_node(uint8_t remoteUnit);
#endif
#if FEATURE_I2C
# if FEATURE_I2C
void format_I2C_port_description(taskIndex_t x);
#endif
#if FEATURE_SPI
void format_SPI_port_description(int8_t spi_gpios[3], uint8_t spi_bus);
#endif
#if FEATURE_I2C
void format_I2C_pin_description(taskIndex_t x);
#endif
#if FEATURE_SPI
void format_SPI_pin_description(int8_t spi_gpios[3], taskIndex_t x, bool showCSpin = true);
#endif
// ********************************************************************************
// Show the task settings page
// ********************************************************************************
void handle_devices_TaskSettingsPage(taskIndex_t taskIndex, uint8_t page);
void devicePage_show_pin_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
#ifdef PLUGIN_USES_SERIAL
void devicePage_show_serial_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
#endif
#if FEATURE_SPI
void devicePage_show_SPI_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
#endif
#if FEATURE_I2C
void devicePage_show_I2C_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
#endif
# if FEATURE_I2CMULTIPLEXER
# if FEATURE_I2CMULTIPLEXER
void ShowI2CMultiplexerUI(uint8_t i2cBus,
bool muxPortsOption,
int taskDeviceI2CMuxPort);
void GetI2CMultiplexerFromPage(uint8_t i2cBus,
bool &muxPortsOption,
int &selectedPorts);
#endif // if FEATURE_I2CMULTIPLEXER
void devicePage_show_output_data_type(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
bool & muxPortsOption,
int & selectedPorts);
# endif // if FEATURE_I2CMULTIPLEXER
# endif // if FEATURE_I2C
#if FEATURE_PLUGIN_STATS
void devicePage_show_task_statistics(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
#endif // if FEATURE_PLUGIN_STATS
void devicePage_show_controller_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
void devicePage_show_interval_config(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
void devicePage_show_task_values(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
void handle_devices();
#endif // ifdef WEBSERVER_DEVICES
#endif
+31 -35
View File
@@ -16,24 +16,8 @@
// ********************************************************************************
// Web Interface download page
// ********************************************************************************
void handle_download() {
# if FEATURE_TARSTREAM_SUPPORT
handle_config_download(false, false);
}
void handle_full_backup() {
handle_config_download(true, false);
}
void handle_full_backup_no_usr_pwd() {
handle_config_download(true, true);
}
void handle_config_download(bool fullBackup,
bool noCreds) {
# else // if FEATURE_TARSTREAM_SUPPORT
const bool noCreds = false;
# endif // if FEATURE_TARSTREAM_SUPPORT
static void handle_config_download(bool fullBackup,
bool noCreds) {
# ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("handle_download"));
# endif // ifndef BUILD_NO_RAM_TRACKER
@@ -84,9 +68,9 @@ void handle_config_download(bool fullBackup,
if (fullBackup && (nullptr != tarStream)) {
const String security_dat = getFileName(FileType::SECURITY_DAT);
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
# if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
const String device_security_dat = getFileName(FileType::DEV_SECURITY_DAT);
#endif
# endif
# if defined(ESP8266)
fs::Dir dir = ESPEASY_FS.openDir("");
@@ -95,12 +79,12 @@ void handle_config_download(bool fullBackup,
fs::File file = dir.openFile("r");
if (file) {
if (!noCreds ||
(noCreds
&& (0 != strncasecmp(file.name(), security_dat.c_str(), security_dat.length()))
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
&& (0 != strncasecmp(file.name(), device_security_dat.c_str(), device_security_dat.length()))
#endif
if (!noCreds ||
(noCreds
&& (0 != strncasecmp(file.name(), security_dat.c_str(), security_dat.length()))
# if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
&& (0 != strncasecmp(file.name(), device_security_dat.c_str(), device_security_dat.length()))
# endif
)) {
tarStream->addFile(file.name(), file.size());
}
@@ -114,12 +98,12 @@ void handle_config_download(bool fullBackup,
while (file) {
if (!file.isDirectory()) {
if (!noCreds ||
(noCreds
&& (0 != strncasecmp(file.name(), security_dat.c_str(), security_dat.length()))
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
&& (0 != strncasecmp(file.name(), device_security_dat.c_str(), device_security_dat.length()))
#endif
if (!noCreds ||
(noCreds
&& (0 != strncasecmp(file.name(), security_dat.c_str(), security_dat.length()))
# if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
&& (0 != strncasecmp(file.name(), device_security_dat.c_str(), device_security_dat.length()))
# endif
)) {
tarStream->addFileIfExists(file.name());
}
@@ -145,10 +129,11 @@ void handle_config_download(bool fullBackup,
if (!noCreds) {
tarStream->addFileIfExists(getFileName(FileType::SECURITY_DAT));
#if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
# if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
// TODO TD-er: Must add separate flag for this
// tarStream->addFileIfExists(getFileName(FileType::DEV_SECURITY_DAT));
#endif
// tarStream->addFileIfExists(getFileName(FileType::DEV_SECURITY_DAT));
# endif // if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
}
// rules<n>.txt files
@@ -195,4 +180,15 @@ void handle_config_download(bool fullBackup,
dataFile.close();
}
void handle_download() { handle_config_download(false, false); }
# if FEATURE_TARSTREAM_SUPPORT
void handle_full_backup() { handle_config_download(true, false); }
void handle_full_backup_no_usr_pwd() { handle_config_download(true, true); }
# endif // if FEATURE_TARSTREAM_SUPPORT
#endif // ifdef WEBSERVER_DOWNLOAD
+1 -8
View File
@@ -1,5 +1,4 @@
#ifndef WEBSERVER_WEBSERVER_DOWNLOADPAGE_H
#define WEBSERVER_WEBSERVER_DOWNLOADPAGE_H
#pragma once
#include "../WebServer/common.h"
@@ -12,11 +11,5 @@ void handle_download();
# if FEATURE_TARSTREAM_SUPPORT
void handle_full_backup();
void handle_full_backup_no_usr_pwd();
void handle_config_download(bool fullBackup,
bool noCreds);
# endif // if FEATURE_TARSTREAM_SUPPORT
#endif // ifdef WEBSERVER_DOWNLOAD
#endif // ifndef WEBSERVER_WEBSERVER_DOWNLOADPAGE_H
+289 -306
View File
@@ -9,7 +9,8 @@
#include "../WebServer/ConfigPage.h"
#include "../WebServer/ControlPage.h"
#include "../WebServer/ControllerPage.h"
//#include "../WebServer/CustomPage.h"
// #include "../WebServer/CustomPage.h"
#include "../WebServer/DevicesPage.h"
#include "../WebServer/DownloadPage.h"
#include "../WebServer/EepromVarPage.h"
@@ -20,11 +21,13 @@
#include "../WebServer/InterfacesPage.h"
#include "../WebServer/I2C_Scanner.h"
#include "../WebServer/JSON.h"
//#include "../WebServer/LoadFromFS.h"
// #include "../WebServer/LoadFromFS.h"
#include "../WebServer/Log.h"
//#include "../WebServer/Markup.h"
//#include "../WebServer/Markup_Buttons.h"
//#include "../WebServer/Markup_Forms.h"
// #include "../WebServer/Markup.h"
// #include "../WebServer/Markup_Buttons.h"
// #include "../WebServer/Markup_Forms.h"
#include "../WebServer/NetworkPage.h"
#include "../WebServer/NotificationPage.h"
#include "../WebServer/PluginListPage.h"
@@ -71,7 +74,6 @@
#include <uri/UriGlob.h>
void safe_strncpy_webserver_arg(char *dest, const String& arg, size_t max_size) {
if (hasArg(arg)) {
safe_strncpy(dest, webArg(arg).c_str(), max_size);
@@ -82,48 +84,6 @@ void safe_strncpy_webserver_arg(char *dest, const __FlashStringHelper *arg, size
safe_strncpy_webserver_arg(dest, String(arg), max_size);
}
void sendHeadandTail(const __FlashStringHelper *tmplName, bool Tail, bool rebooting) {
// This function is called twice per serving a web page.
// So it must keep track of the timer longer than the scope of this function.
// Therefore use a local static variable.
#if FEATURE_TIMING_STATS
static uint64_t statisticsTimerStart = 0;
if (!Tail) {
statisticsTimerStart = getMicros64();
}
#endif // if FEATURE_TIMING_STATS
{
const String fileName = concat(tmplName, F(".htm"));
fs::File f = tryOpenFile(fileName, "r");
WebTemplateParser templateParser(Tail, rebooting);
if (f) {
bool success = true;
while (f.available() && success) {
success = templateParser.process((char)f.read());
}
f.close();
} else {
getWebPageTemplateDefault(tmplName, templateParser);
}
#ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("sendWebPage"));
#endif // ifndef BUILD_NO_RAM_TRACKER
// web activity timer
lastWeb = millis();
}
if (shouldReboot) {
// we only add this here as a seperate chunk to prevent using too much memory at once
serve_JS(JSfiles_e::Reboot);
}
STOP_TIMER(HANDLE_SERVING_WEBPAGE);
}
void sendTail_stdtemplate(bool rebooting) {
sendHeadandTail(F("TmplStd"), _TAIL, rebooting);
TXBuffer.endStream();
@@ -131,31 +91,39 @@ void sendTail_stdtemplate(bool rebooting) {
// We have sent a lot of data at once.
// try to flush it to the connected client to free up some RAM
// from pending transfers
// TXBuffer.flush();
// delay(10);
// TXBuffer.flush();
// delay(10);
}
static bool clientConnectedToAP()
{
const IPAddress client_localIP = web_server.client().localIP();
return IPAddressSet(client_localIP) && client_localIP == apIP;
}
bool captivePortal() {
// We only need to check if a client connected here via AP
// We only need to check if a client connected here via AP
// as currently we don't have any interface which allows forwarding
// packets and thus acting as a gateway for others.
if (!Settings.ApCaptivePortal() || !clientConnectedToAP()) return false;
if (!Settings.ApCaptivePortal() || !clientConnectedToAP()) { return false; }
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, concat(F("CaptivePortal: hostHeader: "), web_server.hostHeader()));
#endif
if (!ESPEasy::net::NetworkConnected())
{
return false;
}
if (!isIP(web_server.hostHeader())
if (!isIP(web_server.hostHeader())
#if FEATURE_MDNS
&& !getValue(LabelType::M_DNS).equalsIgnoreCase(web_server.hostHeader())
#endif
) {
) {
const IPAddress client_localIP = web_server.client().localIP();
String redirectURL = concat(F("http://"), formatIP(client_localIP));
String redirectURL = concat(F("http://"), formatIP(client_localIP));
#ifdef WEBSERVER_SETUP
if (ESPEasy::net::wifi::shouldRedirectTo_setup()) {
@@ -171,28 +139,23 @@ bool captivePortal() {
return false;
}
bool clientConnectedToAP()
{
const IPAddress client_localIP = web_server.client().localIP();
return IPAddressSet(client_localIP) && client_localIP == apIP;
}
ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo()
{
const IPAddress client_localIP = web_server.client().localIP();
if (!IPAddressSet(client_localIP))
/*
ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo()
{
const IPAddress client_localIP = web_server.client().localIP();
if (!IPAddressSet(client_localIP))
return ESPEasy::net::INVALID_NETWORK_INDEX;
if (client_localIP == apIP) {
if (client_localIP == apIP) {
// Easy to check as this is a global variable
return NETWORK_INDEX_WIFI_AP;
}
#ifdef ESP8266
if (client_localIP == WiFi.localIP()) {
}
#ifdef ESP8266
if (client_localIP == WiFi.localIP()) {
return NETWORK_INDEX_WIFI_STA;
}
#endif
#ifdef ESP32
for (ESPEasy::net::networkIndex_t x = 0; x < NETWORK_MAX; ++x) {
}
#endif
#ifdef ESP32
for (ESPEasy::net::networkIndex_t x = 0; x < NETWORK_MAX; ++x) {
if (Settings.getNetworkEnabled(x)) {
struct EventStruct TempEvent;
TempEvent.NetworkIndex = x;
@@ -202,14 +165,14 @@ ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo()
{
const NWPlugin::IP_type ip_types[] = {
NWPlugin::IP_type::inet,
# if CONFIG_LWIP_IPV6
# if CONFIG_LWIP_IPV6
NWPlugin::IP_type::ipv6_unknown,
NWPlugin::IP_type::ipv6_global,
NWPlugin::IP_type::ipv6_link_local,
NWPlugin::IP_type::ipv6_site_local,
NWPlugin::IP_type::ipv6_unique_local,
NWPlugin::IP_type::ipv4_mapped_ipv6,
# endif // if CONFIG_LWIP_IPV6
# endif // if CONFIG_LWIP_IPV6
};
@@ -219,19 +182,19 @@ ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo()
}
}
}
}
}
#endif
return ESPEasy::net::INVALID_NETWORK_INDEX;
}
#endif
return ESPEasy::net::INVALID_NETWORK_INDEX;
}
*/
// ********************************************************************************
// Web Interface init
// ********************************************************************************
// #include "core_version.h"
void WebServerInit()
static void WebServerInit()
{
if (webserver_init) { return; }
webserver_init = true;
@@ -243,7 +206,7 @@ void WebServerInit()
// Entries for several captive portal URLs.
// Maybe not needed. Might be handled by notFound handler.
web_server.on(UriGlob("/generate_204*"), handle_root); // Android captive portal. Handle "/generate_204_<uuid>"-like requests.
//web_server.on(F("/generate_204"), handle_root); // android captive portal redirect
// web_server.on(F("/generate_204"), handle_root); // android captive portal redirect
web_server.on(F("/fwlink"), handle_root); // Microsoft captive portal.
web_server.on(F("/redirect"), handle_root); // microsoft redirect
web_server.on(F("/hotspot-detect.html"), handle_root); // apple call home
@@ -253,10 +216,10 @@ void WebServerInit()
#endif // ifdef WEBSERVER_ROOT
#ifdef WEBSERVER_ADVANCED
web_server.on(F("/advanced"), handle_advanced);
web_server.on(F("/advanced"), handle_advanced);
# if defined(WEBSERVER_DOWNLOAD) && FEATURE_TARSTREAM_SUPPORT
web_server.on(F("/backup"), handle_full_backup);
web_server.on(F("/backupnup"), handle_full_backup_no_usr_pwd);
web_server.on(F("/backup"), handle_full_backup);
web_server.on(F("/backupnup"), handle_full_backup_no_usr_pwd);
# endif // if defined(WEBSERVER_DOWNLOAD) && FEATURE_TARSTREAM_SUPPORT
#endif // ifdef WEBSERVER_ADVANCED
#ifdef WEBSERVER_CONFIG
@@ -286,65 +249,62 @@ void WebServerInit()
#endif // USES_C016
#ifdef WEBSERVER_FACTORY_RESET
web_server.on(F("/factoryreset"), handle_factoryreset);
web_server.on(F("/factoryreset"), handle_factoryreset);
#endif // ifdef WEBSERVER_FACTORY_RESET
#if FEATURE_SETTINGS_ARCHIVE
web_server.on(F("/settingsarchive"), handle_settingsarchive);
web_server.on(F("/settingsarchive"), handle_settingsarchive);
#endif // if FEATURE_SETTINGS_ARCHIVE
#ifdef WEBSERVER_FILELIST
web_server.on(F("/filelist"), handle_filelist);
web_server.on(F("/filelist"), handle_filelist);
#endif // ifdef WEBSERVER_FILELIST
#ifdef WEBSERVER_HARDWARE
web_server.on(F("/hardware"), handle_hardware);
web_server.on(F("/hardware"), handle_hardware);
#endif // ifdef WEBSERVER_HARDWARE
#ifdef WEBSERVER_INTERFACES
web_server.on(F("/interfaces"), handle_interfaces);
#if FEATURE_I2C
web_server.on(F("/interfaces_i2c"), handle_interfaces_i2c);
#endif // if FEATURE_I2C
#if FEATURE_SPI
web_server.on(F("/interfaces_spi"), handle_interfaces_spi);
#endif // if FEATURE_SPI
#if FEATURE_MODBUS && FEATURE_MODBUS_INTERFACES_TAB
web_server.on(F("/interfaces_modbus"), handle_interfaces_modbus);
#endif // if FEATURE_MODBUS
#if FEATURE_CAN
web_server.on(F("/interfaces_can"), handle_interfaces_can);
#endif // if FEATURE_CAN
#if FEATURE_WRMBUS
web_server.on(F("/interfaces_wrmbus"), handle_interfaces_wrmbus);
#endif // if FEATURE_WRMBUS
#if FEATURE_WIMBUS
web_server.on(F("/interfaces_wimbus"), handle_interfaces_wimbus);
#endif // if FEATURE_WIMBUS
web_server.on(F("/interfaces"), handle_interfaces);
# if FEATURE_I2C
web_server.on(F("/interfaces_i2c"), handle_interfaces_i2c);
# endif // if FEATURE_I2C
# if FEATURE_SPI
web_server.on(F("/interfaces_spi"), handle_interfaces_spi);
# endif // if FEATURE_SPI
# if FEATURE_MODBUS && FEATURE_MODBUS_INTERFACES_TAB
web_server.on(F("/interfaces_modbus"), handle_interfaces_modbus);
# endif // if FEATURE_MODBUS
# if FEATURE_CAN
web_server.on(F("/interfaces_can"), handle_interfaces_can);
# endif // if FEATURE_CAN
# if FEATURE_WRMBUS
web_server.on(F("/interfaces_wrmbus"), handle_interfaces_wrmbus);
# endif // if FEATURE_WRMBUS
# if FEATURE_WIMBUS
web_server.on(F("/interfaces_wimbus"), handle_interfaces_wimbus);
# endif // if FEATURE_WIMBUS
#endif // ifdef WEBSERVER_INTERFACES
#ifdef WEBSERVER_I2C_SCANNER
web_server.on(F("/i2cscanner"), handle_i2cscanner);
web_server.on(F("/i2cscanner"), handle_i2cscanner);
#endif // ifdef WEBSERVER_I2C_SCANNER
#ifdef WEBSERVER_JSON
web_server.on(F("/json"), handle_json); // Also part of WEBSERVER_NEW_UI
web_server.on(F("/json"), handle_json); // Also part of WEBSERVER_NEW_UI
#endif
#ifdef WEBSERVER_CSVVAL
web_server.on(F("/csv"), handle_csvval);
web_server.on(F("/csv"), handle_csvval);
#endif
#ifdef WEBSERVER_LOG
web_server.on(F("/log"), handle_log);
web_server.on(F("/logjson"), handle_log_JSON); // Also part of WEBSERVER_NEW_UI
#endif
web_server.on(F("/log"), handle_log);
web_server.on(F("/logjson"), handle_log_JSON); // Also part of WEBSERVER_NEW_UI
#endif // ifdef WEBSERVER_LOG
#if FEATURE_NOTIFIER
web_server.on(F("/notifications"), handle_notifications);
web_server.on(F("/notifications"), handle_notifications);
#endif // if FEATURE_NOTIFIER
#ifdef WEBSERVER_PINSTATES
web_server.on(F("/pinstates"), handle_pinstates);
web_server.on(F("/pinstates"), handle_pinstates);
#endif // ifdef WEBSERVER_PINSTATES
#ifdef WEBSERVER_RULES
web_server.on(F("/rules"), handle_rules_new);
web_server.on(F("/rules/"), Goto_Rules_Root);
web_server.on(F("/rules"), handle_rules_new);
web_server.on(F("/rules/"), Goto_Rules_Root);
# ifdef WEBSERVER_NEW_RULES
web_server.on(F("/rules/add"), []()
{
handle_rules_edit(web_server.uri(), true);
});
web_server.on(F("/rules/add"), handle_rules_add);
web_server.on(F("/rules/backup"), handle_rules_backup);
web_server.on(F("/rules/delete"), handle_rules_delete);
# endif // WEBSERVER_NEW_RULES
@@ -477,7 +437,74 @@ void setWebserverRunning(bool state) {
ESPEasy::net::CheckRunningServices(true); // Uses webserverRunning state.
}
void getWebPageTemplateDefault(const String& tmplName, WebTemplateParser& parser)
static void getWebPageTemplateDefaultHead(WebTemplateParser& parser, bool addMeta, bool addJS) {
if (parser.isTail()) { return; }
parser.process(F("<!DOCTYPE html><html lang='en'>"
"<head>"
"<meta charset='utf-8'/>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<title>{{name}}</title>"));
if (addMeta) { parser.process(F("{{meta}}")); }
if (addJS) { parser.process(F("{{js}}")); }
parser.process(F("{{css}}"
"</head>"));
}
static void getWebPageTemplateDefaultHeader(WebTemplateParser& parser, const __FlashStringHelper *title, bool addMenu) {
{
if (parser.isTail()) { return; }
#ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER
parser.process(strformat(F("<header class='headermenu%c'><h1>ESP Easy Mega: "), isGpMenuSecondLevel(navMenuIndex) ? '2' : ' '));
parser.process(title);
# if BUILD_IN_WEBHEADER
parser.process(F(
"<div style='float:right;font-size:10pt'>Build: " GITHUB_RELEASES_LINK_PREFIX "{{date}}" GITHUB_RELEASES_LINK_SUFFIX
"</div>"));
# endif // #if BUILD_IN_WEBHEADER
parser.process(F("</h1><BR>"));
#else // ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER
String tmp = F(WEBPAGE_TEMPLATE_DEFAULT_HEADER);
tmp.replace(F("{{title}}"), title);
parser.process(tmp);
#endif // ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER
}
if (addMenu) { parser.process(F("{{menu}}")); }
parser.process(F("</header>"));
}
static void getWebPageTemplateDefaultContentSection(WebTemplateParser& parser) {
parser.process(F("<section>"
"<span class='message error'>"
"{{error}}"
"</span>"
"{{content}}"
"</section>"
));
}
static void getWebPageTemplateDefaultFooter(WebTemplateParser& parser) {
if (!parser.isTail()) { return; }
#ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER
parser.process(F("<footer>"
"<br>"
"<h6>Powered by <a href='http://www.letscontrolit.com' style='font-size: 15px; text-decoration: none'>Let's Control It</a> community"
# if BUILD_IN_WEBFOOTER
"<div style='float: right'>Build: " GITHUB_RELEASES_LINK_PREFIX "{{build}} {{date}}" GITHUB_RELEASES_LINK_SUFFIX "</div>"
# endif // #if BUILD_IN_WEBFOOTER
"</h6>"
"</footer>"
"</body></html>"
));
#else // ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER
parser.process(F(WEBPAGE_TEMPLATE_DEFAULT_FOOTER));
#endif // ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER
}
static void getWebPageTemplateDefault(const String& tmplName, WebTemplateParser& parser)
{
const bool addJS = true;
const bool addMeta = true;
@@ -562,71 +589,46 @@ void getWebPageTemplateDefault(const String& tmplName, WebTemplateParser& parser
// addLog(LOG_LEVEL_INFO, concat(F("tmpl.length(): "), tmpl.length()));
}
void getWebPageTemplateDefaultHead(WebTemplateParser& parser, bool addMeta, bool addJS) {
if (parser.isTail()) { return; }
parser.process(F("<!DOCTYPE html><html lang='en'>"
"<head>"
"<meta charset='utf-8'/>"
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"
"<title>{{name}}</title>"));
void sendHeadandTail(const __FlashStringHelper *tmplName, bool Tail, bool rebooting) {
// This function is called twice per serving a web page.
// So it must keep track of the timer longer than the scope of this function.
// Therefore use a local static variable.
#if FEATURE_TIMING_STATS
static uint64_t statisticsTimerStart = 0;
if (addMeta) { parser.process(F("{{meta}}")); }
if (addJS) { parser.process(F("{{js}}")); }
parser.process(F("{{css}}"
"</head>"));
}
void getWebPageTemplateDefaultHeader(WebTemplateParser& parser, const __FlashStringHelper *title, bool addMenu) {
if (!Tail) {
statisticsTimerStart = getMicros64();
}
#endif // if FEATURE_TIMING_STATS
{
if (parser.isTail()) { return; }
#ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER
parser.process(strformat(F("<header class='headermenu%c'><h1>ESP Easy Mega: "), isGpMenuSecondLevel(navMenuIndex) ? '2' : ' '));
parser.process(title);
# if BUILD_IN_WEBHEADER
parser.process(F(
"<div style='float:right;font-size:10pt'>Build: " GITHUB_RELEASES_LINK_PREFIX "{{date}}" GITHUB_RELEASES_LINK_SUFFIX
"</div>"));
# endif // #if BUILD_IN_WEBHEADER
parser.process(F("</h1><BR>"));
#else // ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER
String tmp = F(WEBPAGE_TEMPLATE_DEFAULT_HEADER);
tmp.replace(F("{{title}}"), title);
parser.process(tmp);
#endif // ifndef WEBPAGE_TEMPLATE_DEFAULT_HEADER
const String fileName = concat(tmplName, F(".htm"));
fs::File f = tryOpenFile(fileName, "r");
WebTemplateParser templateParser(Tail, rebooting);
if (f) {
bool success = true;
while (f.available() && success) {
success = templateParser.process((char)f.read());
}
f.close();
} else {
getWebPageTemplateDefault(tmplName, templateParser);
}
#ifndef BUILD_NO_RAM_TRACKER
checkRAM(F("sendWebPage"));
#endif // ifndef BUILD_NO_RAM_TRACKER
// web activity timer
lastWeb = millis();
}
if (addMenu) { parser.process(F("{{menu}}")); }
parser.process(F("</header>"));
}
void getWebPageTemplateDefaultContentSection(WebTemplateParser& parser) {
parser.process(F("<section>"
"<span class='message error'>"
"{{error}}"
"</span>"
"{{content}}"
"</section>"
));
}
void getWebPageTemplateDefaultFooter(WebTemplateParser& parser) {
if (!parser.isTail()) { return; }
#ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER
parser.process(F("<footer>"
"<br>"
"<h6>Powered by <a href='http://www.letscontrolit.com' style='font-size: 15px; text-decoration: none'>Let's Control It</a> community"
# if BUILD_IN_WEBFOOTER
"<div style='float: right'>Build: " GITHUB_RELEASES_LINK_PREFIX "{{build}} {{date}}" GITHUB_RELEASES_LINK_SUFFIX "</div>"
# endif // #if BUILD_IN_WEBFOOTER
"</h6>"
"</footer>"
"</body></html>"
));
#else // ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER
parser.process(F(WEBPAGE_TEMPLATE_DEFAULT_FOOTER));
#endif // ifndef WEBPAGE_TEMPLATE_DEFAULT_FOOTER
if (shouldReboot) {
// we only add this here as a seperate chunk to prevent using too much memory at once
serve_JS(JSfiles_e::Reboot);
}
STOP_TIMER(HANDLE_SERVING_WEBPAGE);
}
void writeDefaultCSS(void)
@@ -669,9 +671,7 @@ void writeDefaultCSS(void)
int8_t level = 0;
int8_t lastLevel = -1;
void json_quote_name(const __FlashStringHelper *val) {
json_quote_name(String(val));
}
void json_quote_name(const __FlashStringHelper *val) { json_quote_name(String(val)); }
void json_quote_name(const String& val) {
if (lastLevel == level) {
@@ -684,13 +684,9 @@ void json_quote_name(const String& val) {
}
}
void json_quote_val(const String& val) {
addHtml(to_json_value(val));
}
void json_quote_val(const String& val) { addHtml(to_json_value(val)); }
void json_open(bool arr) {
json_open(arr, EMPTY_STRING);
}
void json_open(bool arr) { json_open(arr, EMPTY_STRING); }
void json_open(bool arr, const __FlashStringHelper *name) {
json_quote_name(name);
@@ -711,9 +707,7 @@ void json_init() {
lastLevel = -1;
}
void json_close() {
json_close(false);
}
void json_close() { json_close(false); }
void json_close(bool arr) {
addHtml(arr ? ']' : '}');
@@ -721,14 +715,9 @@ void json_close(bool arr) {
lastLevel = level;
}
void json_number(const __FlashStringHelper *name, const String& value)
{
json_prop(name, value);
}
void json_number(const __FlashStringHelper *name, const String& value) { json_prop(name, value); }
void json_number(const String& name, const String& value) {
json_prop(name, value);
}
void json_number(const String& name, const String& value) { json_prop(name, value); }
void json_prop(const __FlashStringHelper *name, const String& value)
{
@@ -743,10 +732,10 @@ void json_prop(const String& name, const String& value) {
lastLevel = level;
}
void json_prop(LabelType::Enum label) {
json_prop(getInternalLabel(label, '-'), getValue(label));
}
#endif
void json_prop(LabelType::Enum label) { json_prop(getInternalLabel(label, '-'), getValue(label)); }
#endif // ifdef WEBSERVER_NEW_UI
// ********************************************************************************
// Add a task select dropdown list
// This allows to select a task index based on the existing tasks.
@@ -761,10 +750,11 @@ void addTaskSelect(const String& name, taskIndex_t choice)
for (taskIndex_t x = 0; x <= TASKS_MAX; x++)
{
deviceNr.clear();
if (validTaskIndex(x)) {
const deviceIndex_t DeviceIndex = getDeviceIndex_from_TaskIndex(x);
deviceName = getPluginNameFromDeviceIndex(DeviceIndex);
deviceNr += (x + 1);
deviceNr += (x + 1);
} else {
deviceName = F("Not Set");
}
@@ -777,7 +767,7 @@ void addTaskSelect(const String& name, taskIndex_t choice)
FormSelectorOptions selector(TASKS_MAX + 1, options, nullptr, attrs);
selector.reloadonchange = true;
selector.classname = F("wide");
selector.classname = F("wide");
selector.addSelector(name, choice);
}
@@ -880,6 +870,7 @@ void startStream_send_stdTemplate_NoLoginCheck(uint8_t newNavIndex, bool rebooti
TXBuffer.startStream();
sendHeadandTail(F("TmplStd"), _HEAD, rebooting);
// TODO TD-er: This should be the only place where sendHeadandTail_stdtemplate(_HEAD) is called
@@ -915,11 +906,10 @@ void startStream_send_stdTemplate_NoLoginCheck(uint8_t newNavIndex, bool rebooti
addLogMove(LOG_LEVEL_INFO, log);
}
}
*/
*/
#endif // ifndef BUILD_NO_DEBUG
}
bool startJSON_Stream()
{
if (!isLoggedIn()) { return false; }
@@ -928,7 +918,6 @@ bool startJSON_Stream()
return true;
}
String getControllerSymbol(uint8_t index)
{
String ret = F("<span style='font-size:20px; background: #00000000;'>&#");
@@ -938,15 +927,15 @@ String getControllerSymbol(uint8_t index)
return ret;
}
void handle_printWebString()
void handle_printWebString()
{
if (printWebString.isEmpty()) return;
if (printWebString.isEmpty()) { return; }
addRowColspan(2);
addHtml(F("Command Output<BR><textarea readonly rows='10' wrap='on'>"));
addHtml(printWebString);
addHtml(F("</textarea>"));
free_string(printWebString);
printToWeb = false;
printToWeb = false;
}
/*
@@ -958,54 +947,35 @@ void handle_printWebString()
return ret;
}
*/
void addSVG_param(const char key, int value)
{
addHtml(strformat(F(" %c=\"%d\""), key, value));
#if FEATURE_CHART_STORAGE_LAYOUT && !defined(BUILD_NO_DEBUG)
static void addSVG_param(const char key, int value) { addHtml(strformat(F(" %c=\"%d\""), key, value)); }
static void addSVG_param(const __FlashStringHelper *key, int value) { addHtml(strformat(F(" %s=\"%d\""), FsP(key), value)); }
#endif // if FEATURE_CHART_STORAGE_LAYOUT && !defined(BUILD_NO_DEBUG)
static void addSVG_param(const char key, const String& value) { addHtml(strformat(F(" %c=\"%s\""), key, value.c_str())); }
static void addSVG_param(const __FlashStringHelper *key, const String& value) {
addHtml(strformat(F(" %s=\"%s\""), FsP(key), value.c_str()));
}
void addSVG_param(const char key, float value)
{
addSVG_param(key, toString(value, 2));
}
static void addSVG_param(const char key, float value) { addSVG_param(key, toString(value, 2)); }
void addSVG_param(const char key, const String& value)
{
addHtml(strformat(F(" %c=\"%s\""), key, value.c_str()));
}
static void addSVG_param(const __FlashStringHelper *key, float value) { addSVG_param(key, toString(value, 2)); }
void addSVG_param(const __FlashStringHelper *key, int value) {
addHtml(strformat(F(" %s=\"%d\""), key, value));
}
void addSVG_param(const __FlashStringHelper *key, float value) {
addSVG_param(key, toString(value, 2));
}
void addSVG_param(const __FlashStringHelper *key, const String& value) {
addHtml(strformat(F(" %s=\"%s\""), key, value.c_str()));
}
void createSvgRect_noStroke(const __FlashStringHelper *classname,
unsigned int fillColor,
float xoffset,
float yoffset,
float width,
float height,
float rx,
float ry) {
createSvgRect(classname, fillColor, fillColor, xoffset, yoffset, width, height, 0, rx, ry);
}
void createSvgRect(const String& classname,
unsigned int fillColor,
unsigned int strokeColor,
float xoffset,
float yoffset,
float width,
float height,
float strokeWidth,
float rx,
float ry) {
static void createSvgRect(const String& classname,
unsigned int fillColor,
unsigned int strokeColor,
float xoffset,
float yoffset,
float width,
float height,
float strokeWidth,
float rx,
float ry) {
addHtml(F("<rect"));
if (!classname.isEmpty()) {
@@ -1026,46 +996,22 @@ void createSvgRect(const String& classname,
addHtml(F("/>"));
}
void createSvgHorRectPath(unsigned int color, int xoffset, int yoffset, int size, int height, int range, float SVG_BAR_WIDTH) {
if (range == 0) {
range = 1;
}
float width = (SVG_BAR_WIDTH * size) / range;
if (width < 2) { width = 2; }
addHtml(formatToHex(color, F("<path fill=\"#")));
addHtml(F("\" d=\"M"));
addHtmlFloat((SVG_BAR_WIDTH * xoffset) / range);
addHtml(' ');
addHtmlInt(yoffset);
addHtml('h');
addHtmlFloat(width);
addHtml('v');
addHtmlInt(height);
addHtml('H');
addHtmlFloat((SVG_BAR_WIDTH * xoffset) / range);
addHtml(F("z\"/>\n"));
static void createSvgRect_noStroke(const __FlashStringHelper *classname,
unsigned int fillColor,
float xoffset,
float yoffset,
float width,
float height,
float rx,
float ry) {
createSvgRect(classname, fillColor, fillColor, xoffset, yoffset, width, height, 0, rx, ry);
}
void createSvgTextElement(const String& text, float textXoffset, float textYoffset) {
addHtml(F("<text"));
addSVG_param('x', textXoffset);
addSVG_param('y', textYoffset);
addHtml('>', '\n');
addHtml(F("<tspan"));
addSVG_param('x', textXoffset);
addSVG_param('y', textYoffset);
addHtml('>');
addHtml(text);
addHtml(F("</tspan>\n</text>"));
}
#define SVG_BAR_HEIGHT 16
#define SVG_BAR_WIDTH 400
void write_SVG_image_header(int width, int height, bool useViewbox) {
static void write_SVG_image_header(int width, int height, bool useViewbox) {
addHtml(F("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\""));
addHtmlInt(width);
addHtml(F("\" height=\""));
@@ -1094,7 +1040,7 @@ void write_SVG_image_header(int width, int height, bool useViewbox) {
}
/*
void getESPeasyLogo(int width_pixels) {
static void getESPeasyLogo(int width_pixels) {
write_SVG_image_header(width_pixels, width_pixels, true);
addHtml(F("<g transform=\"translate(-33.686 -7.8142)\"><rect x=\"49\" y=\"23.1\" width=\"69.3\" height=\"69.3\" fill=\"#2c72da\"
stroke=\"#2c72da\"
@@ -1134,11 +1080,48 @@ void getWiFi_RSSI_icon(int rssi, int width_pixels)
}
#if FEATURE_CHART_STORAGE_LAYOUT && !defined(BUILD_NO_DEBUG)
static void createSvgHorRectPath(unsigned int color, int xoffset, int yoffset, int size, int height, int range, float svg_bar_width) {
if (range == 0) {
range = 1;
}
float width = (svg_bar_width * size) / range;
if (width < 2) { width = 2; }
addHtml(formatToHex(color, F("<path fill=\"#")));
addHtml(F("\" d=\"M"));
addHtmlFloat((svg_bar_width * xoffset) / range);
addHtml(' ');
addHtmlInt(yoffset);
addHtml('h');
addHtmlFloat(width);
addHtml('v');
addHtmlInt(height);
addHtml('H');
addHtmlFloat((svg_bar_width * xoffset) / range);
addHtml(F("z\"/>\n"));
}
static void createSvgTextElement(const String& text, float textXoffset, float textYoffset) {
addHtml(F("<text"));
addSVG_param('x', textXoffset);
addSVG_param('y', textYoffset);
addHtml('>', '\n');
addHtml(F("<tspan"));
addSVG_param('x', textXoffset);
addSVG_param('y', textYoffset);
addHtml('>');
addHtml(text);
addHtml(F("</tspan>\n</text>"));
}
void getConfig_dat_file_layout() {
const int shiftY = 2;
float yOffset = shiftY;
write_SVG_image_header(SVG_BAR_WIDTH + 250, SVG_BAR_HEIGHT + shiftY);
write_SVG_image_header(SVG_BAR_WIDTH + 250, SVG_BAR_HEIGHT + shiftY, false);
int max_index, offset, max_size{};
int struct_size = 0;
@@ -1190,7 +1173,7 @@ void getStorageTableSVG(SettingsType::Enum settingsType) {
if (max_index == 0) { return; }
// One more to add bar indicating struct size vs. reserved space.
write_SVG_image_header(SVG_BAR_WIDTH + 250, (max_index + 1) * SVG_BAR_HEIGHT + shiftY);
write_SVG_image_header(SVG_BAR_WIDTH + 250, (max_index + 1) * SVG_BAR_HEIGHT + shiftY, false);
float yOffset = shiftY;
for (int i = 0; i < max_index; ++i) {
@@ -1229,7 +1212,7 @@ void getStorageTableSVG(SettingsType::Enum settingsType) {
String text = strformat(
F("%s/%s per item"),
formatHumanReadable(struct_size, 1024).c_str(),
formatHumanReadable(max_size, 1024).c_str());
formatHumanReadable(max_size, 1024).c_str());
createSvgTextElement(text, textXoffset, textYoffset);
} else {
createSvgTextElement(F("Variable size"), textXoffset, textYoffset);
@@ -1237,7 +1220,7 @@ void getStorageTableSVG(SettingsType::Enum settingsType) {
addHtml(F("</svg>\n"));
}
void drawPartitionChartSVG(
static void drawPartitionChartSVG(
float yOffset,
uint32_t realSize,
uint32_t partitionAddress,
@@ -1261,7 +1244,6 @@ void drawPartitionChartSVG(
# include <esp_partition.h>
void getPartitionTableSVG(uint8_t pType, unsigned int partitionColor) {
int nrPartitions = getPartionCount(pType);
@@ -1273,11 +1255,12 @@ void getPartitionTableSVG(uint8_t pType, unsigned int partitionColor) {
const esp_partition_t *_mypart;
esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, ESP_PARTITION_SUBTYPE_ANY, nullptr);
write_SVG_image_header(SVG_BAR_WIDTH + 250, nrPartitions * SVG_BAR_HEIGHT + shiftY);
write_SVG_image_header(SVG_BAR_WIDTH + 250, nrPartitions * SVG_BAR_HEIGHT + shiftY, false);
float yOffset = shiftY;
if (_mypartiterator) {
do {
do
{
_mypart = esp_partition_get(_mypartiterator);
drawPartitionChartSVG(
yOffset,
@@ -1297,12 +1280,13 @@ void getPartitionTableSVG(uint8_t pType, unsigned int partitionColor) {
# endif // ifdef ESP32
# ifdef ESP8266
void getPartitionTableSVG() {
// sketch / OTA / FS / EEPROM / RFcal / wifi
const int nrPartitions = 6;
const int shiftY = 2;
write_SVG_image_header(SVG_BAR_WIDTH + 250, nrPartitions * SVG_BAR_HEIGHT + shiftY);
write_SVG_image_header(SVG_BAR_WIDTH + 250, nrPartitions * SVG_BAR_HEIGHT + shiftY, false);
float yOffset = shiftY;
for (int i = 0; i < nrPartitions; ++i) {
@@ -1315,7 +1299,8 @@ void getPartitionTableSVG() {
String descr;
unsigned int partitionColor = 0xab56e6;
switch (ptype) {
switch (ptype)
{
case ESP8266_partition_type::sketch:
label = F("sketch");
partitionColor = 0xab56e6;
@@ -1375,6 +1360,4 @@ void getPartitionTableSVG() {
# endif // ifdef ESP8266
#endif // if FEATURE_CHART_STORAGE_LAYOUT
bool webArg2ip(const __FlashStringHelper *arg, uint8_t *IP) {
return str2ip(webArg(arg), IP);
}
bool webArg2ip(const __FlashStringHelper *arg, uint8_t *IP) { return str2ip(webArg(arg), IP); }
+37 -107
View File
@@ -14,51 +14,35 @@
// Uncrustify must not be used on macros, but we're now done, so turn Uncrustify on again.
// *INDENT-ON*
void safe_strncpy_webserver_arg(char *dest, const String& arg, size_t max_size);
void safe_strncpy_webserver_arg(char *dest,
const String& arg,
size_t max_size);
void safe_strncpy_webserver_arg(char *dest, const __FlashStringHelper * arg, size_t max_size);
void safe_strncpy_webserver_arg(char *dest,
const __FlashStringHelper *arg,
size_t max_size);
void sendHeadandTail(const __FlashStringHelper * tmplName,
bool Tail = false,
bool rebooting = false);
void sendHeadandTail(const __FlashStringHelper *tmplName,
bool Tail = false,
bool rebooting = false);
void sendTail_stdtemplate(bool rebooting = false);
void sendTail_stdtemplate(bool rebooting = false);
void WebServerInit();
// ********************************************************************************
// Redirect to captive portal if we got a request for another domain.
// Redirect to captive portal if we got a request for another domain.
// Return true in that case so the page handler does not try to handle the request again.
// ********************************************************************************
bool captivePortal();
bool clientConnectedToAP();
bool captivePortal();
// Determine which network interface is being used by the client to access this ESPEasy node
ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo();
// ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo();
void setWebserverRunning(bool state);
void getWebPageTemplateDefault(const String& tmplName,
WebTemplateParser& parser);
void getWebPageTemplateDefaultHead(WebTemplateParser& parser,
bool addMeta,
bool addJS);
void getWebPageTemplateDefaultHeader(WebTemplateParser& parser,
const __FlashStringHelper * title,
bool addMenu);
void getWebPageTemplateDefaultContentSection(WebTemplateParser& parser);
void getWebPageTemplateDefaultFooter(WebTemplateParser& parser);
void setWebserverRunning(bool state);
void writeDefaultCSS(void);
void writeDefaultCSS(void);
// ********************************************************************************
@@ -70,15 +54,15 @@ void writeDefaultCSS(void);
extern int8_t level;
extern int8_t lastLevel;
void json_quote_name(const __FlashStringHelper * val);
void json_quote_name(const __FlashStringHelper *val);
void json_quote_name(const String& val);
void json_quote_val(const String& val);
void json_open(bool arr = false);
void json_open(bool arr,
const __FlashStringHelper * name);
void json_open(bool arr,
const __FlashStringHelper *name);
void json_open(bool arr,
const String& name);
@@ -89,26 +73,26 @@ void json_close();
void json_close(bool arr);
void json_number(const __FlashStringHelper * name,
const String& value);
void json_number(const __FlashStringHelper *name,
const String & value);
void json_number(const String& name,
const String& value);
void json_prop(const __FlashStringHelper * name,
const String& value);
void json_prop(const __FlashStringHelper *name,
const String & value);
void json_prop(const String& name,
const String& value);
void json_prop(LabelType::Enum label);
#endif
#endif // ifdef WEBSERVER_NEW_UI
// ********************************************************************************
// Add a task select dropdown list
// This allows to select a task index based on the existing tasks.
// When changing a selected task, the page reloads with the new settings applied.
// However, these changes will not trigger a save, so make sure to store those in
// However, these changes will not trigger a save, so make sure to store those in
// PCONFIG() and not in extra settings
// ********************************************************************************
void addTaskSelect(const String& name,
@@ -131,77 +115,23 @@ bool isLoggedIn(bool mustProvideLogin = true);
// Thus not for non-HTML pages.
bool startStream_send_stdTemplate(uint8_t newNavIndex);
void startStream_send_stdTemplate_NoLoginCheck(uint8_t newNavIndex, bool rebooting = false);
void startStream_send_stdTemplate_NoLoginCheck(uint8_t newNavIndex,
bool rebooting = false);
// Check isLoggedIn and start JSON stream
// JSON can be called from anywhere, so no need to update the nav index
bool startJSON_Stream();
bool startJSON_Stream();
String getControllerSymbol(uint8_t index);
String getControllerSymbol(uint8_t index);
void handle_printWebString();
void handle_printWebString();
/*
String getValueSymbol(uint8_t index);
*/
void addSVG_param(const char key,
int value);
void addSVG_param(const char key,
float value);
void addSVG_param(const char key,
const String& value);
void addSVG_param(const __FlashStringHelper * key,
int value);
void addSVG_param(const __FlashStringHelper * key,
float value);
void addSVG_param(const __FlashStringHelper * key,
const String& value);
void createSvgRect_noStroke(const __FlashStringHelper * classname,
unsigned int fillColor,
float xoffset,
float yoffset,
float width,
float height,
float rx,
float ry);
void createSvgRect(const String& classname,
unsigned int fillColor,
unsigned int strokeColor,
float xoffset,
float yoffset,
float width,
float height,
float strokeWidth,
float rx,
float ry);
void createSvgHorRectPath(unsigned int color,
int xoffset,
int yoffset,
int size,
int height,
int range,
float SVG_BAR_WIDTH);
void createSvgTextElement(const String& text,
float textXoffset,
float textYoffset);
void write_SVG_image_header(int width,
int height,
bool useViewbox = false);
/*
void getESPeasyLogo(int width_pixels);
*/
void getWiFi_RSSI_icon(int rssi,
int width_pixels);
@@ -210,20 +140,20 @@ void getConfig_dat_file_layout();
void getStorageTableSVG(SettingsType::Enum settingsType);
#ifdef ESP32
# ifdef ESP32
void getPartitionTableSVG(uint8_t pType,
unsigned int partitionColor);
#endif // ifdef ESP32
#ifdef ESP8266
# endif // ifdef ESP32
# ifdef ESP8266
void getPartitionTableSVG();
#endif
# endif
#endif
#endif // if FEATURE_CHART_STORAGE_LAYOUT && !defined(BUILD_NO_DEBUG)
bool webArg2ip(const __FlashStringHelper * arg,
uint8_t *IP);
bool webArg2ip(const __FlashStringHelper *arg,
uint8_t *IP);
#endif // ifndef WEBSERVER_ESPEASY_WEBSERVER_H
#endif // ifndef WEBSERVER_ESPEASY_WEBSERVER_H
+23 -19
View File
@@ -17,6 +17,29 @@
#include "../Helpers/ESPEasy_Storage.h"
#include "../Helpers/Hardware.h"
// ********************************************************************************
// Create pre-defined config selector
// ********************************************************************************
#ifndef LIMIT_BUILD_SIZE
static void addPreDefinedConfigSelector() {
DeviceModel active_model = ResetFactoryDefaultPreference.getDeviceModel();
addSelector_Head_reloadOnChange(F("fdm"));
for (uint8_t x = 0; x < static_cast<uint8_t>(DeviceModel::DeviceModel_MAX); ++x) {
DeviceModel model = static_cast<DeviceModel>(x);
if (modelMatchingFlashSize(model)) {
addSelector_Item(
getDeviceModelString(model),
x,
model == active_model);
}
}
addSelector_Foot(true);
}
#endif
// ********************************************************************************
// Web Interface Factory Reset
// ********************************************************************************
@@ -110,25 +133,6 @@ void handle_factoryreset() {
sendTail_stdtemplate();
}
// ********************************************************************************
// Create pre-defined config selector
// ********************************************************************************
void addPreDefinedConfigSelector() {
DeviceModel active_model = ResetFactoryDefaultPreference.getDeviceModel();
addSelector_Head_reloadOnChange(F("fdm"));
for (uint8_t x = 0; x < static_cast<uint8_t>(DeviceModel::DeviceModel_MAX); ++x) {
DeviceModel model = static_cast<DeviceModel>(x);
if (modelMatchingFlashSize(model)) {
addSelector_Item(
getDeviceModelString(model),
x,
model == active_model);
}
}
addSelector_Foot(true);
}
#ifdef WEBSERVER_NEW_UI
void handle_factoryreset_json() {
-4
View File
@@ -12,10 +12,6 @@
// ********************************************************************************
void handle_factoryreset();
// ********************************************************************************
// Create pre-defined config selector
// ********************************************************************************
void addPreDefinedConfigSelector();
#ifdef WEBSERVER_NEW_UI
void handle_factoryreset_json();
Loaded 100 of 131 files, more files were not shown because too many files have changed in this diff. Show more