mirror of
https://github.com/letscontrolit/ESPEasy.git
synced 2026-10-26 22:10:45 +00:00
Merge pull request #5656 from TD-er/build/use_cpp_static_functiondecl
[Build] Reduce build size using static functions
This commit is contained in:
131 files changed
+6143
-6363
No files matched your search
@@ -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,14 +61,14 @@ 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,
|
||||
static String getNetworkParameterDisplayName(networkDriverIndex_t NetworkDriverIndex,
|
||||
NetworkSettingsStruct::VarType parameterIdx,
|
||||
bool & isAlternative) {
|
||||
bool displayName = true;
|
||||
@@ -91,6 +91,7 @@ void addNetworkEnabledForm(networkIndex_t networkindex) {
|
||||
addFormCheckBox(displayName, internalName, Settings.getNetworkEnabled(networkindex));
|
||||
}
|
||||
|
||||
/*
|
||||
void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
|
||||
networkIndex_t networkindex,
|
||||
NetworkSettingsStruct::VarType varType) {
|
||||
@@ -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);
|
||||
*/
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ void addNetworkParameterForm(const NetworkSettingsStruct & NetworkSettings,
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,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");
|
||||
|
||||
@@ -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[]
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
+1131
-1044
File diff suppressed because it is too large.
Load diff
@@ -14,7 +14,7 @@
|
||||
String EventToFileName(const String& eventName);
|
||||
|
||||
String FileNameToEvent(const String& fileName);
|
||||
#endif
|
||||
#endif // ifdef WEBSERVER_NEW_RULES
|
||||
|
||||
void checkRuleSets();
|
||||
|
||||
@@ -39,85 +39,12 @@ bool rulesProcessingFile(const String& fileName,
|
||||
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
|
||||
\*********************************************************************************************/
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "../Helpers/StringConverter.h"
|
||||
#include "../WebServer/ESPEasy_WebServer.h"
|
||||
|
||||
void updateLoopStats() {
|
||||
static void updateLoopStats() {
|
||||
++loopCounter;
|
||||
++loopCounter_full;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -53,6 +53,7 @@ struct Dallas_SensorData {
|
||||
# ifndef LIMIT_BUILD_SIZE
|
||||
bool parasitePowered{};
|
||||
# endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -77,17 +78,11 @@ 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);
|
||||
|
||||
uint64_t Dallas_addr_to_uint64(const uint8_t addr[]);
|
||||
|
||||
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,
|
||||
@@ -102,17 +97,11 @@ void Dallas_addr_selector_webform_save(taskIndex_t TaskIndex,
|
||||
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,33 +177,23 @@ 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,
|
||||
int8_t gpio_pin_tx);
|
||||
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,
|
||||
int8_t gpio_pin_rx,
|
||||
int8_t gpio_pin_tx);
|
||||
@@ -242,26 +204,7 @@ void Dallas_write_bit_ISR(uint8_t v,
|
||||
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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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!");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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(',');
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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"));
|
||||
|
||||
@@ -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,7 +1482,7 @@ String getCNonce(const int len) {
|
||||
return s;
|
||||
}
|
||||
|
||||
String getDigestAuth(const String& authReq,
|
||||
static String getDigestAuth(const String& authReq,
|
||||
const String& username,
|
||||
const String& password,
|
||||
const String& method,
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -31,7 +31,6 @@ void runEach30Seconds();
|
||||
#if FEATURE_MQTT
|
||||
|
||||
void scheduleNextMQTTdelayQueue();
|
||||
void schedule_all_MQTTimport_tasks();
|
||||
|
||||
void processMQTTdelayQueue();
|
||||
|
||||
|
||||
@@ -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("//"));
|
||||
|
||||
+190
-111
@@ -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)
|
||||
{
|
||||
@@ -30,21 +98,21 @@ bool RulesCalculate_t::is_number(char oc, char c, char pc)
|
||||
((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.
|
||||
&& (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 || (
|
||||
|
||||
return op == UnaryOperator::Not || (
|
||||
c >= static_cast<char>(UnaryOperator::Log) &&
|
||||
c <= static_cast<char>(UnaryOperator::ArcTan_d)));
|
||||
c <= static_cast<char>(UnaryOperator::ArcTan_d));
|
||||
|
||||
/*
|
||||
switch (op) {
|
||||
case UnaryOperator::Not:
|
||||
@@ -74,12 +142,14 @@ bool RulesCalculate_t::is_unary_operator(char c)
|
||||
}
|
||||
|
||||
#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,14 +268,15 @@ 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
|
||||
ret = asin(first);
|
||||
# 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:
|
||||
@@ -212,7 +284,7 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
|
||||
ret = acos(first);
|
||||
# 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:
|
||||
@@ -220,7 +292,7 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_unary_operator(char op, ESPEASY
|
||||
ret = atan(first);
|
||||
# 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
|
||||
return sin(first);
|
||||
# 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
|
||||
return cos(first);
|
||||
# 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
|
||||
return tan(first);
|
||||
# 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,20 +355,23 @@ 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 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
|
||||
ret = atan2(first, second);
|
||||
# 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
|
||||
@@ -305,6 +382,7 @@ ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_binary_operator(char op, ESPEAS
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
|
||||
|
||||
ESPEASY_RULES_FLOAT_TYPE RulesCalculate_t::apply_quinary_operator(char op,
|
||||
@@ -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,6 +429,7 @@ 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;
|
||||
@@ -360,6 +439,7 @@ CalculateReturnCode RulesCalculate_t::RPNCalculate(char *token)
|
||||
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;
|
||||
@@ -371,6 +451,7 @@ CalculateReturnCode RulesCalculate_t::RPNCalculate(char *token)
|
||||
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
|
||||
@@ -383,11 +464,14 @@ 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));
|
||||
@@ -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)
|
||||
@@ -433,6 +525,7 @@ bool RulesCalculate_t::op_left_assoc(const char c)
|
||||
{
|
||||
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
|
||||
@@ -493,14 +586,18 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
|
||||
// Get peek-ahead char
|
||||
pcpos = strpos + 1;
|
||||
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,6 +661,21 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
|
||||
*(TokenPos) = 0; // Mark end of token string
|
||||
error = RPNCalculate(token);
|
||||
TokenPos = token;
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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) ||
|
||||
@@ -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)
|
||||
@@ -680,6 +808,7 @@ CalculateReturnCode RulesCalculate_t::doCalculate(const char *input, ESPEASY_RUL
|
||||
// addLog(LOG_LEVEL_INFO, strformat(F("doCalculate closing up stack sl: %u token: %s sc: %d"), sl, token, sc));
|
||||
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)
|
||||
@@ -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;
|
||||
|
||||
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
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# define TOKEN_LENGTH 40
|
||||
#else
|
||||
# define TOKEN_LENGTH 25
|
||||
#endif
|
||||
#endif // if FEATURE_USE_DOUBLE_AS_ESPEASY_RULES_FLOAT_TYPE
|
||||
#define OPERATOR_STACK_SIZE 32
|
||||
|
||||
enum class CalculateReturnCode : uint8_t {
|
||||
@@ -24,6 +24,7 @@ enum class CalculateReturnCode : uint8_t{
|
||||
ERROR_PARENTHESES_MISMATCHED = 3u,
|
||||
ERROR_UNKNOWN_TOKEN = 4u,
|
||||
ERROR_TOKEN_LENGTH_EXCEEDED = 5u
|
||||
|
||||
};
|
||||
|
||||
bool isError(CalculateReturnCode returnCode);
|
||||
@@ -56,6 +57,7 @@ enum class UnaryOperator : uint8_t {
|
||||
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
|
||||
@@ -64,19 +66,20 @@ enum class BinaryOperator : uint8_t {
|
||||
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);
|
||||
#if !defined(LIMIT_BUILD_SIZE) && FEATURE_TRIGONOMETRIC_FUNCTIONS_RULES
|
||||
bool angleDegree(BinaryOperator op);
|
||||
const __FlashStringHelper* toString(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]{};
|
||||
@@ -86,19 +89,19 @@ private:
|
||||
// Check if it matches part of a number (identifier)
|
||||
// @param oc Previous character
|
||||
// @param c Current character
|
||||
bool is_number(char oc,
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -150,8 +153,7 @@ public:
|
||||
// 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
|
||||
+460
-442
File diff suppressed because it is too large.
Load diff
+107
-119
@@ -22,35 +22,57 @@ 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) {
|
||||
@@ -76,25 +98,37 @@ String concat(const String& str, const T &val) {
|
||||
}
|
||||
*/
|
||||
|
||||
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.
|
||||
@@ -112,9 +146,10 @@ bool equals(const String& str, const T &val) {
|
||||
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,
|
||||
...);
|
||||
|
||||
|
||||
/********************************************************************************************\
|
||||
@@ -128,8 +163,8 @@ bool str2ip(const String& string,
|
||||
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);
|
||||
@@ -140,19 +175,23 @@ const __FlashStringHelper * boolToString(bool value);
|
||||
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);
|
||||
|
||||
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 = ' ');
|
||||
|
||||
|
||||
/*********************************************************************************************\
|
||||
@@ -191,8 +230,10 @@ 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);
|
||||
String formatIntLeadingZeroes(int value,
|
||||
int nrDigits);
|
||||
String formatIntLeadingZeroes(const String& value,
|
||||
int nrDigits);
|
||||
|
||||
/*********************************************************************************************\
|
||||
Wrap a string with given pre- and postfix string.
|
||||
@@ -203,7 +244,8 @@ String wrap_String(const String& string,
|
||||
char wrap);
|
||||
|
||||
String wrap_String(const String& string,
|
||||
char char1, char char2);
|
||||
char char1,
|
||||
char char2);
|
||||
|
||||
String wrapIfContains(const String& value,
|
||||
char contains,
|
||||
@@ -219,20 +261,16 @@ String wrapWithQuotesIfContainsParameterSeparatorChar(const String& text);
|
||||
String to_json_value(const String& value,
|
||||
bool wrapInQuotes = false);
|
||||
|
||||
bool is_json_formatted(const String& value);
|
||||
|
||||
/*********************************************************************************************\
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
@@ -393,7 +437,7 @@ void parseUniqueIdVariable(String & s,
|
||||
void parseElementIdVariable(String & s,
|
||||
const String& elementId,
|
||||
bool useURLencode);
|
||||
#endif
|
||||
#endif // if FEATURE_MQTT_DISCOVER
|
||||
|
||||
#if FEATURE_STRING_VARIABLES
|
||||
void parseValNameVariable(String & s,
|
||||
@@ -408,56 +452,12 @@ void parseEventVariables(String & s,
|
||||
struct EventStruct *event,
|
||||
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);
|
||||
|
||||
#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);
|
||||
@@ -474,23 +474,11 @@ bool GetArgv(const char *string,
|
||||
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 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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -392,7 +392,7 @@ int Plugin_QueryVType_Temperature(uint8_t value_nr) { return static_cast<i
|
||||
|
||||
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,48 +468,233 @@ 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)) {
|
||||
return tmpTopic;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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, concat(strformat(F("MQTT : AutoDiscovery for Controller %d CPlugin %d"),
|
||||
ControllerIndex + 1, CPluginID),
|
||||
validTaskIndex(mqttDiscoverOnlyTask) ?
|
||||
strformat(F(", Task %d"), mqttDiscoverOnlyTask + 1) :
|
||||
EMPTY_STRING));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// Dispatch autoDiscovery per supported CPlugin
|
||||
switch (CPluginID)
|
||||
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)
|
||||
{
|
||||
case 5: // CPLUGIN_ID_005 : Home assistant/openHAB
|
||||
success = MQTT_HomeAssistant_SendAutoDiscovery(ControllerIndex, *ControllerSettings);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
static bool MQTT_HomeAssistant_SendAutoDiscovery(controllerIndex_t ControllerIndex,
|
||||
ControllerSettingsStruct& ControllerSettings) {
|
||||
bool success = false;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,6 +16,7 @@ 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
|
||||
@@ -25,12 +26,13 @@ String generate_external_URL(const String& fname, bool isEmbedded) {
|
||||
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);
|
||||
|
||||
// Use 'onerror' to try to reload the CSS when first attempt loading failed
|
||||
@@ -48,20 +50,20 @@ void serve_CDN_CSS(const __FlashStringHelper * fname, const __FlashStringHelper
|
||||
// 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>"),
|
||||
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,
|
||||
static void serve_CDN_JS(const __FlashStringHelper *fname,
|
||||
const __FlashStringHelper *script_arg,
|
||||
bool useDefer) {
|
||||
addHtml(F("<script"));
|
||||
|
||||
if (useDefer) {
|
||||
addHtml(F(" defer"));
|
||||
}
|
||||
@@ -72,16 +74,17 @@ void serve_CDN_JS(const __FlashStringHelper * fname,
|
||||
html_add_script_end();
|
||||
}
|
||||
|
||||
|
||||
void serve_CSS(CSSfiles_e cssfile) {
|
||||
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)
|
||||
@@ -94,7 +97,7 @@ void serve_CSS(CSSfiles_e cssfile) {
|
||||
url = F("codemirror.min.css");
|
||||
useCDN = true;
|
||||
break;
|
||||
#endif
|
||||
#endif // if FEATURE_RULES_EASY_COLOR_CODE
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@@ -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() {
|
||||
@@ -136,30 +141,39 @@ void serve_favicon() {
|
||||
addHtmlAttribute(F("href"), generate_external_URL(F("favicon.ico"), true));
|
||||
addHtml('/', '>');
|
||||
*/
|
||||
#endif
|
||||
#endif // ifdef WEBSERVER_FAVICON_CDN
|
||||
#ifndef LIMIT_BUILD_SIZE
|
||||
addHtml(F("<link"));
|
||||
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" />
|
||||
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
|
||||
#endif // ifndef LIMIT_BUILD_SIZE
|
||||
}
|
||||
|
||||
void serve_JS(JSfiles_e JSfile) {
|
||||
const __FlashStringHelper *url = F("");
|
||||
const __FlashStringHelper *id = F("");
|
||||
bool useDefer = true;
|
||||
|
||||
#if defined(WEBSERVER_INCLUDE_JS)
|
||||
bool useCDN = false;
|
||||
#endif
|
||||
|
||||
switch (JSfile) {
|
||||
switch (JSfile)
|
||||
{
|
||||
case JSfiles_e::UpdateSensorValuesDevicePage:
|
||||
url = F("update_sensor_values_device_page.js");
|
||||
break;
|
||||
@@ -204,7 +218,7 @@ void serve_JS(JSfiles_e JSfile) {
|
||||
useCDN = true;
|
||||
# endif
|
||||
break;
|
||||
#endif
|
||||
#endif // if FEATURE_RULES_EASY_COLOR_CODE
|
||||
#ifdef USES_P113
|
||||
case JSfiles_e::P113_script:
|
||||
url = F("p113_script.js");
|
||||
@@ -227,9 +241,12 @@ void serve_JS(JSfiles_e JSfile) {
|
||||
if (!fileExists(fname))
|
||||
{
|
||||
#if defined(WEBSERVER_INCLUDE_JS)
|
||||
|
||||
if (!useCDN) {
|
||||
html_add_script_arg(id, useDefer);
|
||||
switch (JSfile) {
|
||||
|
||||
switch (JSfile)
|
||||
{
|
||||
case JSfiles_e::UpdateSensorValuesDevicePage:
|
||||
# ifdef WEBSERVER_DEVICES
|
||||
TXBuffer.addFlashString((PGM_P)FPSTR(DATA_UPDATE_SENSOR_VALUES_DEVICE_PAGE_JS));
|
||||
@@ -255,12 +272,14 @@ void serve_JS(JSfiles_e JSfile) {
|
||||
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;
|
||||
@@ -269,7 +288,7 @@ void serve_JS(JSfiles_e JSfile) {
|
||||
case JSfiles_e::EasyColorCode_espeasy:
|
||||
case JSfiles_e::EasyColorCode_cm_plugins:
|
||||
break;
|
||||
#endif
|
||||
# endif // if FEATURE_RULES_EASY_COLOR_CODE
|
||||
# ifdef USES_P113
|
||||
case JSfiles_e::P113_script:
|
||||
TXBuffer.addFlashString((PGM_P)FPSTR(p113_script));
|
||||
@@ -284,7 +303,7 @@ void serve_JS(JSfiles_e JSfile) {
|
||||
html_add_script_end();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif // if defined(WEBSERVER_INCLUDE_JS)
|
||||
serve_CDN_JS(url, id, useDefer);
|
||||
} else {
|
||||
serve_CDN_JS(fname, id, useDefer);
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
//-V::569
|
||||
|
||||
String generate_external_URL(const String& fname);
|
||||
|
||||
void serve_favicon();
|
||||
|
||||
enum class JSfiles_e {
|
||||
|
||||
@@ -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→3h)") : F("End (localtime, e.g. 3h→2h)"),
|
||||
isStart ? F("dststarthour") : F("dstendhour"),
|
||||
rule.hour, 0, 23);
|
||||
addUnit(isStart ? F("hour ↷") : F("hour ↶"));
|
||||
}
|
||||
|
||||
|
||||
#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→3h)") : F("End (localtime, e.g. 3h→2h)"),
|
||||
isStart ? F("dststarthour") : F("dstendhour"),
|
||||
rule.hour, 0, 23);
|
||||
addUnit(isStart ? F("hour ↷") : F("hour ↶"));
|
||||
}
|
||||
|
||||
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
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
+866
-836
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,4 @@
|
||||
#ifndef WEBSERVER_WEBSERVER_DEVICESPAGE_H
|
||||
#define WEBSERVER_WEBSERVER_DEVICESPAGE_H
|
||||
#pragma once
|
||||
|
||||
#include "../WebServer/common.h"
|
||||
|
||||
@@ -11,63 +10,8 @@
|
||||
# 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
|
||||
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
|
||||
void ShowI2CMultiplexerUI(uint8_t i2cBus,
|
||||
@@ -77,21 +21,8 @@ void GetI2CMultiplexerFromPage(uint8_t i2cBus,
|
||||
bool & muxPortsOption,
|
||||
int & selectedPorts);
|
||||
# endif // if FEATURE_I2CMULTIPLEXER
|
||||
# endif // if FEATURE_I2C
|
||||
|
||||
void devicePage_show_output_data_type(taskIndex_t taskIndex, deviceIndex_t DeviceIndex);
|
||||
|
||||
#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
|
||||
@@ -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,
|
||||
static void handle_config_download(bool fullBackup,
|
||||
bool noCreds) {
|
||||
# else // if FEATURE_TARSTREAM_SUPPORT
|
||||
const bool noCreds = false;
|
||||
# endif // if FEATURE_TARSTREAM_SUPPORT
|
||||
# ifndef BUILD_NO_RAM_TRACKER
|
||||
checkRAM(F("handle_download"));
|
||||
# endif // ifndef BUILD_NO_RAM_TRACKER
|
||||
@@ -146,9 +130,10 @@ void handle_config_download(bool fullBackup,
|
||||
if (!noCreds) {
|
||||
tarStream->addFileIfExists(getFileName(FileType::SECURITY_DAT));
|
||||
# if FEATURE_STORE_CREDENTIALS_SEPARATE_FILE
|
||||
|
||||
// TODO TD-er: Must add separate flag for this
|
||||
// tarStream->addFileIfExists(getFileName(FileType::DEV_SECURITY_DAT));
|
||||
#endif
|
||||
# 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,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
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "../WebServer/ConfigPage.h"
|
||||
#include "../WebServer/ControlPage.h"
|
||||
#include "../WebServer/ControllerPage.h"
|
||||
|
||||
// #include "../WebServer/CustomPage.h"
|
||||
#include "../WebServer/DevicesPage.h"
|
||||
#include "../WebServer/DownloadPage.h"
|
||||
@@ -20,8 +21,10 @@
|
||||
#include "../WebServer/InterfacesPage.h"
|
||||
#include "../WebServer/I2C_Scanner.h"
|
||||
#include "../WebServer/JSON.h"
|
||||
|
||||
// #include "../WebServer/LoadFromFS.h"
|
||||
#include "../WebServer/Log.h"
|
||||
|
||||
// #include "../WebServer/Markup.h"
|
||||
// #include "../WebServer/Markup_Buttons.h"
|
||||
// #include "../WebServer/Markup_Forms.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();
|
||||
@@ -135,15 +95,23 @@ void sendTail_stdtemplate(bool rebooting) {
|
||||
// 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
|
||||
// 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;
|
||||
@@ -171,12 +139,7 @@ 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();
|
||||
@@ -224,14 +187,14 @@ ESPEasy::net::networkIndex_t getNetworkIndex_ClientConnectsTo()
|
||||
#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;
|
||||
@@ -330,7 +293,7 @@ void WebServerInit()
|
||||
#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
|
||||
#endif // ifdef WEBSERVER_LOG
|
||||
#if FEATURE_NOTIFIER
|
||||
web_server.on(F("/notifications"), handle_notifications);
|
||||
#endif // if FEATURE_NOTIFIER
|
||||
@@ -341,10 +304,7 @@ void WebServerInit()
|
||||
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>"));
|
||||
if (!Tail) {
|
||||
statisticsTimerStart = getMicros64();
|
||||
}
|
||||
|
||||
void getWebPageTemplateDefaultHeader(WebTemplateParser& parser, const __FlashStringHelper *title, bool addMenu) {
|
||||
#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>"));
|
||||
if (shouldReboot) {
|
||||
// we only add this here as a seperate chunk to prevent using too much memory at once
|
||||
serve_JS(JSfiles_e::Reboot);
|
||||
}
|
||||
|
||||
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
|
||||
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,6 +750,7 @@ 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);
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -919,7 +910,6 @@ void startStream_send_stdTemplate_NoLoginCheck(uint8_t newNavIndex, bool rebooti
|
||||
#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;'>&#");
|
||||
@@ -940,7 +929,7 @@ String getControllerSymbol(uint8_t index)
|
||||
|
||||
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);
|
||||
@@ -958,45 +947,26 @@ 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,
|
||||
static void createSvgRect(const String& classname,
|
||||
unsigned int fillColor,
|
||||
unsigned int strokeColor,
|
||||
float xoffset,
|
||||
@@ -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) {
|
||||
@@ -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); }
|
||||
@@ -14,9 +14,13 @@
|
||||
// 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,
|
||||
@@ -25,38 +29,18 @@ void sendHeadandTail(const __FlashStringHelper * tmplName,
|
||||
void sendTail_stdtemplate(bool rebooting = false);
|
||||
|
||||
|
||||
void WebServerInit();
|
||||
|
||||
// ********************************************************************************
|
||||
// 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();
|
||||
|
||||
// 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 writeDefaultCSS(void);
|
||||
|
||||
@@ -102,7 +86,7 @@ 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
|
||||
@@ -131,7 +115,8 @@ 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
|
||||
@@ -145,63 +130,8 @@ 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);
|
||||
|
||||
@@ -220,7 +150,7 @@ void getPartitionTableSVG(uint8_t pType,
|
||||
void getPartitionTableSVG();
|
||||
# endif
|
||||
|
||||
#endif
|
||||
#endif // if FEATURE_CHART_STORAGE_LAYOUT && !defined(BUILD_NO_DEBUG)
|
||||
|
||||
bool webArg2ip(const __FlashStringHelper *arg,
|
||||
uint8_t *IP);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
Reference in new issue
Block a user