[Cleanup] Move structs to separate .h/.cpp files

This commit is contained in:
Gijs Noorlander
2019-09-04 02:23:31 +02:00
parent 237df8abd9
commit beb7fee65b
45 changed files with 2864 additions and 2372 deletions
+1
View File
@@ -14,4 +14,5 @@ struct CRCStruct{
uint32_t numberOfCRCBytes=0;
};
#endif // DATASTRUCTS_CRCSTRUCT_H
+2 -1
View File
@@ -1,6 +1,7 @@
#include "DataStructs/ControllerSettingsStruct.h"
#include "ESPEasy_common.h"
#include "ESPEasy_fdwdecl.h"
#include "DataStructs/ControllerSettingsStruct.h"
#include "DataStructs/ESPEasyLimits.h"
#include "DataStructs/ESPEasyDefaults.h"
+28 -1
View File
@@ -5,6 +5,8 @@
* ControllerSettingsStruct definition
\*********************************************************************************************/
#include <Arduino.h>
#include <memory> // For std::shared_ptr
class IPAddress;
class WiFiClient;
class WiFiUDP;
@@ -24,6 +26,31 @@ class WiFiUDP;
#define CONTROLLER_CLIENTTIMEOUT_DFLT 100
// ********************************************************************************
// IDs of controller settings, used to generate web forms
// ********************************************************************************
#define CONTROLLER_USE_DNS 1
#define CONTROLLER_HOSTNAME 2
#define CONTROLLER_IP 3
#define CONTROLLER_PORT 4
#define CONTROLLER_USER 5
#define CONTROLLER_PASS 6
#define CONTROLLER_MIN_SEND_INTERVAL 7
#define CONTROLLER_MAX_QUEUE_DEPTH 8
#define CONTROLLER_MAX_RETRIES 9
#define CONTROLLER_FULL_QUEUE_ACTION 10
#define CONTROLLER_CHECK_REPLY 12
#define CONTROLLER_SUBSCRIBE 13
#define CONTROLLER_PUBLISH 14
#define CONTROLLER_LWT_TOPIC 15
#define CONTROLLER_LWT_CONNECT_MESSAGE 16
#define CONTROLLER_LWT_DISCONNECT_MESSAGE 17
#define CONTROLLER_TIMEOUT 18
#define CONTROLLER_SAMPLE_SET_INITIATOR 19
#define CONTROLLER_ENABLED 20 // Keep this as last, is used to loop over all parameters
struct ControllerSettingsStruct
{
ControllerSettingsStruct();
@@ -74,5 +101,5 @@ private:
typedef std::shared_ptr<ControllerSettingsStruct> ControllerSettingsStruct_ptr_type;
#define MakeControllerSettings(T) ControllerSettingsStruct_ptr_type ControllerSettingsStruct_ptr(new ControllerSettingsStruct());\
ControllerSettingsStruct& T = *ControllerSettingsStruct_ptr;
#endif // DATASTRUCTS_CONTROLLERSETTINGSSTRUCT_H
+66
View File
@@ -0,0 +1,66 @@
#ifndef DATASTRUCTS_DEVICESTRUCTS_H
#define DATASTRUCTS_DEVICESTRUCTS_H
#include <Arduino.h>
#include <vector>
#define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin
#define DEVICE_TYPE_DUAL 2 // connected through 2 datapins
#define DEVICE_TYPE_TRIPLE 3 // connected through 3 datapins
#define DEVICE_TYPE_ANALOG 10 // AIN/tout pin
#define DEVICE_TYPE_I2C 20 // connected through I2C
#define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection
// Used for VType
#define SENSOR_TYPE_NONE 0
#define SENSOR_TYPE_SINGLE 1
#define SENSOR_TYPE_TEMP_HUM 2
#define SENSOR_TYPE_TEMP_BARO 3
#define SENSOR_TYPE_TEMP_HUM_BARO 4
#define SENSOR_TYPE_DUAL 5
#define SENSOR_TYPE_TRIPLE 6
#define SENSOR_TYPE_QUAD 7
#define SENSOR_TYPE_TEMP_EMPTY_BARO 8
#define SENSOR_TYPE_SWITCH 10
#define SENSOR_TYPE_DIMMER 11
#define SENSOR_TYPE_LONG 20
#define SENSOR_TYPE_WIND 21
#define SENSOR_TYPE_STRING 22
/*********************************************************************************************\
* DeviceStruct
\*********************************************************************************************/
struct DeviceStruct
{
DeviceStruct() :
Number(0), Type(0), VType(SENSOR_TYPE_NONE), Ports(0), ValueCount(0),
PullUpOption(false), InverseLogicOption(false), FormulaOption(false),
Custom(false), SendDataOption(false), GlobalSyncOption(false),
TimerOption(false), TimerOptional(false), DecimalsOnly(false) {}
bool connectedToGPIOpins() {
return (Type >= DEVICE_TYPE_SINGLE && Type <= DEVICE_TYPE_TRIPLE);
}
byte Number; // Plugin ID number. (PLUGIN_ID_xxx)
byte Type; // How the device is connected. e.g. DEVICE_TYPE_SINGLE => connected through 1 datapin
byte VType; // Type of value the plugin will return, used only for Domoticz
byte Ports; // Port to use when device has multiple I/O pins (N.B. not used much)
byte ValueCount; // The number of output values of a plugin. The value should match the number of keys PLUGIN_VALUENAME1_xxx
bool PullUpOption : 1; // Allow to set internal pull-up resistors.
bool InverseLogicOption : 1; // Allow to invert the boolean state (e.g. a switch)
bool FormulaOption : 1; // Allow to enter a formula to convert values during read. (not possible with Custom enabled)
bool Custom : 1;
bool SendDataOption : 1; // Allow to send data to a controller.
bool GlobalSyncOption : 1; // No longer used. Was used for ESPeasy values sync between nodes
bool TimerOption : 1; // Allow to set the "Interval" timer for the plugin.
bool TimerOptional : 1; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay)
bool DecimalsOnly : 1; // Allow to set the number of decimals (otherwise treated a 0 decimals)
};
typedef std::vector<DeviceStruct> DeviceVector;
DeviceVector Device;
#endif // DATASTRUCTS_DEVICESTRUCTS_H
-5
View File
@@ -183,11 +183,6 @@
#define DEFAULT_USE_DST false // (true|false) Use Daily Time Saving
#endif
#define LOG_TO_SERIAL 1
#define LOG_TO_SYSLOG 2
#define LOG_TO_WEBLOG 3
#define LOG_TO_SDCARD 4
#ifndef DEFAULT_SYSLOG_IP
#define DEFAULT_SYSLOG_IP "" // Syslog IP Address
#endif
+52 -13
View File
@@ -1,15 +1,11 @@
#ifndef DATASTRUCTS_ESPEASY_LIMITS_H
#define DATASTRUCTS_ESPEASY_LIMITS_H
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define DEVICES_MAX 95
#else
#ifdef ESP32
#define DEVICES_MAX 85
#else
#define DEVICES_MAX 60
#endif
#endif
// ***********************************************************************
// * These limits have direct impact on the settings files
// * Do not change them!
// * Else settings files will no longer be compatible with official builds
// ***********************************************************************
#if defined(ESP8266)
#define TASKS_MAX 12 // max 12!
@@ -23,25 +19,68 @@
#define CONTROLLER_MAX 3 // max 4!
#define NOTIFICATION_MAX 3 // max 4!
#define VARS_PER_TASK 4
#define PLUGIN_MAX DEVICES_MAX
#define PLUGIN_CONFIGVAR_MAX 8
#define PLUGIN_CONFIGFLOATVAR_MAX 4
#define PLUGIN_CONFIGLONGVAR_MAX 4
#define PLUGIN_EXTRACONFIGVAR_MAX 16
#define NAME_FORMULA_LENGTH_MAX 40
// ***********************************************************************
// * The next limits affect memory usage
// ***********************************************************************
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define DEVICES_MAX 95
#else
#ifdef ESP32
#define DEVICES_MAX 85
#else
#define DEVICES_MAX 60
#endif
#endif
#define PLUGIN_MAX DEVICES_MAX
#define CPLUGIN_MAX 20
#define NPLUGIN_MAX 4
#define UNIT_MAX 254 // unit 255 = broadcast
#define CUSTOM_VARS_MAX 16
// ***********************************************************************
// * Limits regarding Rules
// ***********************************************************************
#define RULES_TIMER_MAX 8
//#define PINSTATE_TABLE_MAX 32
#define RULES_MAX_SIZE 2048
#define RULES_MAX_NESTING_LEVEL 3
#define RULESETS_MAX 4
#define RULES_BUFFER_SIZE 64
#define NAME_FORMULA_LENGTH_MAX 40
#define RULES_IF_MAX_NESTING_LEVEL 4
#define CUSTOM_VARS_MAX 16
#define RULES_IF_MAX_NESTING_LEVEL 4
#define INPUT_COMMAND_SIZE 240 // Affects maximum command length in rules and other commands
// FIXME TD-er: INPUT_COMMAND_SIZE is also used in commands where simply a check for valid parameter is needed
// and some may need less memory. (which is stack allocated)
// ***********************************************************************
// * Other operational limits
// ***********************************************************************
#define MAX_FLASHWRITES_PER_DAY 100 // per 24 hour window
#define UDP_PACKETSIZE_MAX 2048
#define TIMER_GRATUITOUS_ARP_MAX 5000
#define UNIT_NUMBER_MAX 9999 // Stored in Settings.Unit
#define DOMOTICZ_MAX_IDX 999999999 // Looks like it is an unsigned int, so could be up to 4 bln.
@@ -0,0 +1,73 @@
#include "DataStructs/ExtraTaskSettingsStruct.h"
#include "ESPEasy_common.h"
ExtraTaskSettingsStruct::ExtraTaskSettingsStruct() : TaskIndex(TASKS_MAX) {
clear();
}
void ExtraTaskSettingsStruct::clear() {
TaskIndex = TASKS_MAX;
ZERO_FILL(TaskDeviceName);
for (byte i = 0; i < VARS_PER_TASK; ++i) {
TaskDeviceValueDecimals[i] = 2;
ZERO_FILL(TaskDeviceFormula[i]);
ZERO_FILL(TaskDeviceValueNames[i]);
}
for (byte i = 0; i < PLUGIN_EXTRACONFIGVAR_MAX; ++i) {
TaskDevicePluginConfigLong[i] = 0;
TaskDevicePluginConfig[i] = 0;
}
}
void ExtraTaskSettingsStruct::validate() {
ZERO_TERMINATE(TaskDeviceName);
for (byte i = 0; i < VARS_PER_TASK; ++i) {
ZERO_TERMINATE(TaskDeviceFormula[i]);
ZERO_TERMINATE(TaskDeviceValueNames[i]);
}
}
bool ExtraTaskSettingsStruct::checkUniqueValueNames() const {
for (int i = 0; i < (VARS_PER_TASK - 1); ++i) {
for (int j = i; j < VARS_PER_TASK; ++j) {
if (i != j && TaskDeviceValueNames[i][0] != 0) {
if (strcasecmp(TaskDeviceValueNames[i], TaskDeviceValueNames[j]) == 0)
return false;
}
}
}
return true;
}
void ExtraTaskSettingsStruct::clearUnusedValueNames(byte usedVars) {
for (byte i = usedVars; i < VARS_PER_TASK; ++i) {
TaskDeviceValueDecimals[i] = 2;
ZERO_FILL(TaskDeviceFormula[i]);
ZERO_FILL(TaskDeviceValueNames[i]);
}
}
bool ExtraTaskSettingsStruct::checkInvalidCharInNames(const char* name) const {
int pos = 0;
while (*(name+pos) != 0) {
switch (*(name+pos)) {
case ',':
case ' ':
case '#':
case '[':
case ']':
return false;
}
++pos;
}
return true;
}
bool ExtraTaskSettingsStruct::checkInvalidCharInNames() const {
if (!checkInvalidCharInNames(&TaskDeviceName[0])) return false;
for (int i = 0; i < (VARS_PER_TASK - 1); ++i) {
if (!checkInvalidCharInNames(&TaskDeviceValueNames[i][0])) return false;
}
return true;
}
+42
View File
@@ -0,0 +1,42 @@
#ifndef DATASTRUCTS_EXTRATASKSETTINGSSTRUCT_H
#define DATASTRUCTS_EXTRATASKSETTINGSSTRUCT_H
/*********************************************************************************************\
* ExtraTaskSettingsStruct
\*********************************************************************************************/
#include <Arduino.h>
#include "DataStructs/ESPEasyLimits.h"
// This is only used by some plugins to store extra settings like formula descriptions.
// These settings can only be active for one plugin, meaning they have to be loaded
// over and over again from flash when another active plugin uses these values.
//FIXME @TD-er: Should think of another mechanism to make this more efficient.
struct ExtraTaskSettingsStruct
{
ExtraTaskSettingsStruct();
void clear();
void validate();
bool checkUniqueValueNames() const;
void clearUnusedValueNames(byte usedVars);
bool checkInvalidCharInNames(const char* name) const;
bool checkInvalidCharInNames() const;
byte TaskIndex; // Always < TASKS_MAX
char TaskDeviceName[NAME_FORMULA_LENGTH_MAX + 1];
char TaskDeviceFormula[VARS_PER_TASK][NAME_FORMULA_LENGTH_MAX + 1];
char TaskDeviceValueNames[VARS_PER_TASK][NAME_FORMULA_LENGTH_MAX + 1];
long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX];
byte TaskDeviceValueDecimals[VARS_PER_TASK];
int16_t TaskDevicePluginConfig[PLUGIN_EXTRACONFIGVAR_MAX];
};
#endif // DATASTRUCTS_EXTRATASKSETTINGSSTRUCT_H
+102
View File
@@ -0,0 +1,102 @@
#include "DataStructs/LogStruct.h"
#include "ESPEasy_fdwdecl.h"
LogStruct::LogStruct() : write_idx(0), read_idx(0), lastReadTimeStamp(0) {
for (int i = 0; i < LOG_STRUCT_MESSAGE_LINES; ++i) {
timeStamp[i] = 0;
log_level[i] = 0;
}
}
void LogStruct::add(const byte loglevel, const char *line) {
write_idx = (write_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
if (write_idx == read_idx) {
// Buffer full, move read_idx to overwrite oldest entry.
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
}
timeStamp[write_idx] = millis();
log_level[write_idx] = loglevel;
unsigned linelength = strlen(line);
if (linelength > LOG_STRUCT_MESSAGE_SIZE-1)
linelength = LOG_STRUCT_MESSAGE_SIZE-1;
Message[write_idx] = "";
Message[write_idx].reserve(linelength);
for (unsigned i = 0; i < linelength; ++i) {
Message[write_idx] += *(line + i);
}
}
// Read the next item and append it to the given string.
// Returns whether new lines are available.
bool LogStruct::get(String& output, const String& lineEnd) {
lastReadTimeStamp = millis();
if (!isEmpty()) {
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
output += formatLine(read_idx, lineEnd);
}
return !isEmpty();
}
String LogStruct::get_logjson_formatted(bool& logLinesAvailable, unsigned long& timestamp) {
lastReadTimeStamp = millis();
logLinesAvailable = false;
if (isEmpty()) {
return "";
}
read_idx = (read_idx + 1) % LOG_STRUCT_MESSAGE_LINES;
timestamp = timeStamp[read_idx];
String output = logjson_formatLine(read_idx);
if (isEmpty()) return output;
output += ",\n";
logLinesAvailable = true;
return output;
}
bool LogStruct::isEmpty() {
return (write_idx == read_idx);
}
bool LogStruct::logActiveRead() {
clearExpiredEntries();
return timePassedSince(lastReadTimeStamp) < LOG_BUFFER_EXPIRE;
}
String LogStruct::formatLine(int index, const String& lineEnd) {
String output;
output += timeStamp[index];
output += " : ";
output += Message[index];
output += lineEnd;
return output;
}
String LogStruct::logjson_formatLine(int index) {
String output;
output.reserve(LOG_STRUCT_MESSAGE_SIZE + 64);
output = "{";
output += to_json_object_value("timestamp", String(timeStamp[index]));
output += ",\n";
output += to_json_object_value("text", Message[index]);
output += ",\n";
output += to_json_object_value("level", String(log_level[index]));
output += "}";
return output;
}
void LogStruct::clearExpiredEntries() {
if (isEmpty()) {
return;
}
if (timePassedSince(lastReadTimeStamp) > LOG_BUFFER_EXPIRE) {
// Clear the entire log.
// If web log is the only log active, it will not be checked again until it is read.
for (read_idx = 0; read_idx < LOG_STRUCT_MESSAGE_LINES; ++read_idx) {
Message[read_idx] = String(); // Free also the reserved memory.
timeStamp[read_idx] = 0;
log_level[read_idx] = 0;
}
read_idx = 0;
write_idx = 0;
}
}
+55
View File
@@ -0,0 +1,55 @@
#ifndef DATASTRUCTS_LOGSTRUCT_H
#define DATASTRUCTS_LOGSTRUCT_H
#include <Arduino.h>
/*********************************************************************************************\
* LogStruct
\*********************************************************************************************/
#define LOG_STRUCT_MESSAGE_SIZE 128
#ifdef ESP32
#define LOG_STRUCT_MESSAGE_LINES 30
#define LOG_BUFFER_EXPIRE 30000 // Time after which a buffered log item is considered expired.
#else
#if defined(PLUGIN_BUILD_TESTING) || defined(PLUGIN_BUILD_DEV)
#define LOG_STRUCT_MESSAGE_LINES 10
#else
#define LOG_STRUCT_MESSAGE_LINES 15
#endif
#define LOG_BUFFER_EXPIRE 5000 // Time after which a buffered log item is considered expired.
#endif
struct LogStruct {
LogStruct();
void add(const byte loglevel, const char *line);
// Read the next item and append it to the given string.
// Returns whether new lines are available.
bool get(String& output, const String& lineEnd);
String get_logjson_formatted(bool& logLinesAvailable, unsigned long& timestamp);
bool isEmpty();
bool logActiveRead();
private:
String formatLine(int index, const String& lineEnd);
String logjson_formatLine(int index);
void clearExpiredEntries();
String Message[LOG_STRUCT_MESSAGE_LINES];
unsigned long timeStamp[LOG_STRUCT_MESSAGE_LINES];
int write_idx;
int read_idx;
unsigned long lastReadTimeStamp;
byte log_level[LOG_STRUCT_MESSAGE_LINES];
};
#endif // DATASTRUCTS_LOGSTRUCT_H
+29
View File
@@ -0,0 +1,29 @@
#ifndef DATASTRUCTS_NODESTRUCT_H
#define DATASTRUCTS_NODESTRUCT_H
#include "ESPEasy_common.h"
#include <map>
#include <IPAddress.h>
/*********************************************************************************************\
* NodeStruct
\*********************************************************************************************/
struct NodeStruct
{
NodeStruct() :
build(0), age(0), nodeType(0)
{
for (byte i = 0; i < 4; ++i) { ip[i] = 0; }
}
String nodeName;
IPAddress ip;
uint16_t build;
byte age;
byte nodeType;
};
typedef std::map<byte, NodeStruct> NodesMap;
NodesMap Nodes;
#endif // DATASTRUCTS_NODESTRUCT_H
@@ -0,0 +1,26 @@
#include "DataStructs/NotificationSettingsStruct.h"
#include "ESPEasy_common.h"
NotificationSettingsStruct::NotificationSettingsStruct() : Port(0), Pin1(0), Pin2(0) {
ZERO_FILL(Server);
ZERO_FILL(Domain);
ZERO_FILL(Sender);
ZERO_FILL(Receiver);
ZERO_FILL(Subject);
ZERO_FILL(Body);
ZERO_FILL(User);
ZERO_FILL(Pass);
}
void NotificationSettingsStruct::validate() {
ZERO_TERMINATE(Server);
ZERO_TERMINATE(Domain);
ZERO_TERMINATE(Sender);
ZERO_TERMINATE(Receiver);
ZERO_TERMINATE(Subject);
ZERO_TERMINATE(Body);
ZERO_TERMINATE(User);
ZERO_TERMINATE(Pass);
}
@@ -0,0 +1,34 @@
#ifndef DATASTRUCTS_NOTIFICATIONSETTINGSSTRUCT_H
#define DATASTRUCTS_NOTIFICATIONSETTINGSSTRUCT_H
#include <Arduino.h>
#include <memory> // For std::shared_ptr
/*********************************************************************************************\
* NotificationSettingsStruct
\*********************************************************************************************/
struct NotificationSettingsStruct
{
NotificationSettingsStruct();
void validate();
char Server[65];
unsigned int Port;
char Domain[65];
char Sender[65];
char Receiver[65];
char Subject[129];
char Body[513];
byte Pin1;
byte Pin2;
char User[49];
char Pass[33];
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
};
typedef std::shared_ptr<NotificationSettingsStruct> NotificationSettingsStruct_ptr_type;
#define MakeNotificationSettings(T) NotificationSettingsStruct_ptr_type NotificationSettingsStruct_ptr(new NotificationSettingsStruct());\
NotificationSettingsStruct& T = *NotificationSettingsStruct_ptr;
#endif // DATASTRUCTS_NOTIFICATIONSETTINGSSTRUCT_H
+19
View File
@@ -0,0 +1,19 @@
#ifndef DATASTRUCTS_NOTIFICATIONSTRUCT_H
#define DATASTRUCTS_NOTIFICATIONSTRUCT_H
/*********************************************************************************************\
* NotificationStruct
\*********************************************************************************************/
struct NotificationStruct
{
NotificationStruct() :
Number(0), usesMessaging(false), usesGPIO(0) {}
byte Number;
boolean usesMessaging;
byte usesGPIO;
};
#endif // DATASTRUCTS_NOTIFICATIONSTRUCT_H
+30
View File
@@ -0,0 +1,30 @@
#ifndef DATASTRUCTS_PORTSTATUSSTRUCT_H
#define DATASTRUCTS_PORTSTATUSSTRUCT_H
#include "ESPEasy_common.h"
#include <map>
struct portStatusStruct {
portStatusStruct() : state(-1), output(-1), command(0), init(0), mode(0), task(0), monitor(0), forceMonitor(0), forceEvent(0), previousTask(
-1), x(-1) {}
int8_t state : 2; // -1,0,1
int8_t output : 2; // -1,0,1
int8_t command : 2; // 0,1
int8_t init : 2; // 0,1
uint8_t mode : 3; // 6 current values (max. 8)
uint8_t task : 2; // 0-3 (max. 4)
uint8_t monitor : 1; // 0,1
uint8_t forceMonitor : 1; // 0,1
uint8_t forceEvent : 1; // 0,1
int8_t previousTask : 8;
int8_t x; // used to synchronize the Plugin_prt vector index (x) with the PLUGIN_ID
};
std::map<uint32_t, portStatusStruct> globalMapPortStatus;
#endif // DATASTRUCTS_PORTSTATUSSTRUCT_H
+35
View File
@@ -0,0 +1,35 @@
#ifndef DATASTRUCTS_PROTOCOLSTRUCT_H
#define DATASTRUCTS_PROTOCOLSTRUCT_H
#include "ESPEasy_common.h"
#include <vector>
/*********************************************************************************************\
* ProtocolStruct
\*********************************************************************************************/
struct ProtocolStruct
{
ProtocolStruct() :
defaultPort(0), Number(0), usesMQTT(false), usesAccount(false), usesPassword(false),
usesTemplate(false), usesID(false), Custom(false), usesHost(true), usesPort(true),
usesQueue(true), usesSampleSets(false) {}
uint16_t defaultPort;
byte Number;
bool usesMQTT : 1;
bool usesAccount : 1;
bool usesPassword : 1;
bool usesTemplate : 1; // When set, the protocol will pre-load some templates like default MQTT topics
bool usesID : 1; // Whether a controller supports sending an IDX value sent along with plugin data
bool Custom : 1; // When set, the controller has to define all parameters on the controller setup page
bool usesHost : 1;
bool usesPort : 1;
bool usesQueue : 1;
bool usesSampleSets : 1;
};
typedef std::vector<ProtocolStruct> ProtocolVector;
ProtocolVector Protocol;
#endif // DATASTRUCTS_PROTOCOLSTRUCT_H
+36
View File
@@ -0,0 +1,36 @@
#ifndef DATASTRUCTS_RTC_STRUCTS_H
#define DATASTRUCTS_RTC_STRUCTS_H
#include "ESPEasy_common.h"
// this offsets are in blocks, bytes = blocks * 4
#define RTC_BASE_STRUCT 64
#define RTC_BASE_USERVAR 74
#define RTC_BASE_CACHE 124
#define RTC_CACHE_DATA_SIZE 240
#define CACHE_FILE_MAX_SIZE 24000
/*********************************************************************************************\
* RTCStruct
\*********************************************************************************************/
//max 40 bytes: ( 74 - 64 ) * 4
struct RTCStruct
{
RTCStruct() : ID1(0), ID2(0), unused1(false), factoryResetCounter(0),
deepSleepState(0), bootFailedCount(0), flashDayCounter(0),
flashCounter(0), bootCounter(0), lastMixedSchedulerId(0) {}
byte ID1;
byte ID2;
boolean unused1;
byte factoryResetCounter;
byte deepSleepState;
byte bootFailedCount;
byte flashDayCounter;
unsigned long flashCounter;
unsigned long bootCounter;
unsigned long lastMixedSchedulerId;
};
#endif // DATASTRUCTS_RTC_STRUCTS_H
+32
View File
@@ -0,0 +1,32 @@
#include "DataStructs/SecurityStruct.h"
#include "ESPEasy_common.h"
#include "DataStructs/ESPEasyLimits.h"
SecurityStruct::SecurityStruct() {
ZERO_FILL(WifiSSID);
ZERO_FILL(WifiKey);
ZERO_FILL(WifiSSID2);
ZERO_FILL(WifiKey2);
ZERO_FILL(WifiAPKey);
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
ZERO_FILL(ControllerUser[i]);
ZERO_FILL(ControllerPassword[i]);
}
ZERO_FILL(Password);
}
void SecurityStruct::validate() {
ZERO_TERMINATE(WifiSSID);
ZERO_TERMINATE(WifiKey);
ZERO_TERMINATE(WifiSSID2);
ZERO_TERMINATE(WifiKey2);
ZERO_TERMINATE(WifiAPKey);
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
ZERO_TERMINATE(ControllerUser[i]);
ZERO_TERMINATE(ControllerPassword[i]);
}
ZERO_TERMINATE(Password);
}
+5 -24
View File
@@ -1,37 +1,17 @@
#ifndef DATASTRUCTS_SECURITYSTRUCT_H
#define DATASTRUCTS_SECURITYSTRUCT_H
#include "ESPEasy_common.h"
#include "DataStructs/ESPEasyLimits.h"
/*********************************************************************************************\
* SecurityStruct
\*********************************************************************************************/
struct SecurityStruct
{
SecurityStruct() {
ZERO_FILL(WifiSSID);
ZERO_FILL(WifiKey);
ZERO_FILL(WifiSSID2);
ZERO_FILL(WifiKey2);
ZERO_FILL(WifiAPKey);
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
ZERO_FILL(ControllerUser[i]);
ZERO_FILL(ControllerPassword[i]);
}
ZERO_FILL(Password);
}
SecurityStruct();
void validate() {
ZERO_TERMINATE(WifiSSID);
ZERO_TERMINATE(WifiKey);
ZERO_TERMINATE(WifiSSID2);
ZERO_TERMINATE(WifiKey2);
ZERO_TERMINATE(WifiAPKey);
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
ZERO_TERMINATE(ControllerUser[i]);
ZERO_TERMINATE(ControllerPassword[i]);
}
ZERO_TERMINATE(Password);
}
void validate();
char WifiSSID[32];
char WifiKey[64];
@@ -50,4 +30,5 @@ struct SecurityStruct
uint8_t md5[16] = {0};
};
#endif // DATASTRUCTS_SECURITYSTRUCT_H
+2
View File
@@ -160,4 +160,6 @@ SettingsStruct* SettingsStruct_ptr = new SettingsStruct;
SettingsStruct& Settings = *SettingsStruct_ptr;
*/
#endif // DATASTRUCTS_SETTINGSSTRUCT_H
+28
View File
@@ -0,0 +1,28 @@
#ifndef DATASTRUCTS_SYSTEMTIMERSTRUCT_H
#define DATASTRUCTS_SYSTEMTIMERSTRUCT_H
#include "ESPEasy_common.h"
#include <map>
/*********************************************************************************************\
* systemTimerStruct
\*********************************************************************************************/
struct systemTimerStruct
{
systemTimerStruct() :
timer(0), Par1(0), Par2(0), Par3(0), Par4(0), Par5(0), TaskIndex(-1), plugin(0) {}
unsigned long timer;
int Par1;
int Par2;
int Par3;
int Par4;
int Par5;
int16_t TaskIndex;
byte plugin;
};
std::map<unsigned long, systemTimerStruct> systemTimers;
#endif // DATASTRUCTS_SYSTEMTIMERSTRUCT_H
+213
View File
@@ -0,0 +1,213 @@
#include "DataStructs/TimingStats.h"
#include "ESPEasy_common.h"
#include "ESPEasy_plugindefs.h"
#include "_CPlugin_Helper.h"
TimingStats::TimingStats() : _timeTotal(0.0), _count(0), _maxVal(0), _minVal(4294967295) {}
void TimingStats::add(unsigned long time) {
_timeTotal += time;
++_count;
if (time > _maxVal) { _maxVal = time; }
if (time < _minVal) { _minVal = time; }
}
void TimingStats::reset() {
_timeTotal = 0.0;
_count = 0;
_maxVal = 0;
_minVal = 4294967295;
}
bool TimingStats::isEmpty() const {
return _count == 0;
}
float TimingStats::getAvg() const {
if (_count == 0) { return 0.0; }
return _timeTotal / _count;
}
unsigned int TimingStats::getMinMax(unsigned long& minVal, unsigned long& maxVal) const {
if (_count == 0) {
minVal = 0;
maxVal = 0;
return 0;
}
minVal = _minVal;
maxVal = _maxVal;
return _count;
}
bool TimingStats::thresholdExceeded(unsigned long threshold) const {
if (_count == 0) {
return false;
}
return _maxVal > threshold;
}
/********************************************************************************************\
Functions used for displaying timing stats
\*********************************************************************************************/
String getPluginFunctionName(int function) {
switch (function) {
case PLUGIN_INIT_ALL: return F("INIT_ALL");
case PLUGIN_INIT: return F("INIT");
case PLUGIN_READ: return F("READ");
case PLUGIN_ONCE_A_SECOND: return F("ONCE_A_SECOND");
case PLUGIN_TEN_PER_SECOND: return F("TEN_PER_SECOND");
case PLUGIN_DEVICE_ADD: return F("DEVICE_ADD");
case PLUGIN_EVENTLIST_ADD: return F("EVENTLIST_ADD");
case PLUGIN_WEBFORM_SAVE: return F("WEBFORM_SAVE");
case PLUGIN_WEBFORM_LOAD: return F("WEBFORM_LOAD");
case PLUGIN_WEBFORM_SHOW_VALUES: return F("WEBFORM_SHOW_VALUES");
case PLUGIN_GET_DEVICENAME: return F("GET_DEVICENAME");
case PLUGIN_GET_DEVICEVALUENAMES: return F("GET_DEVICEVALUENAMES");
case PLUGIN_WRITE: return F("WRITE");
case PLUGIN_EVENT_OUT: return F("EVENT_OUT");
case PLUGIN_WEBFORM_SHOW_CONFIG: return F("WEBFORM_SHOW_CONFIG");
case PLUGIN_SERIAL_IN: return F("SERIAL_IN");
case PLUGIN_UDP_IN: return F("UDP_IN");
case PLUGIN_CLOCK_IN: return F("CLOCK_IN");
case PLUGIN_TIMER_IN: return F("TIMER_IN");
case PLUGIN_FIFTY_PER_SECOND: return F("FIFTY_PER_SECOND");
case PLUGIN_SET_CONFIG: return F("SET_CONFIG");
case PLUGIN_GET_DEVICEGPIONAMES: return F("GET_DEVICEGPIONAMES");
case PLUGIN_EXIT: return F("EXIT");
case PLUGIN_GET_CONFIG: return F("GET_CONFIG");
case PLUGIN_UNCONDITIONAL_POLL: return F("UNCONDITIONAL_POLL");
case PLUGIN_REQUEST: return F("REQUEST");
}
return getUnknownString();
}
bool mustLogFunction(int function) {
switch (function) {
case PLUGIN_INIT_ALL: return false;
case PLUGIN_INIT: return false;
case PLUGIN_READ: return true;
case PLUGIN_ONCE_A_SECOND: return true;
case PLUGIN_TEN_PER_SECOND: return true;
case PLUGIN_DEVICE_ADD: return false;
case PLUGIN_EVENTLIST_ADD: return false;
case PLUGIN_WEBFORM_SAVE: return false;
case PLUGIN_WEBFORM_LOAD: return false;
case PLUGIN_WEBFORM_SHOW_VALUES: return false;
case PLUGIN_GET_DEVICENAME: return false;
case PLUGIN_GET_DEVICEVALUENAMES: return false;
case PLUGIN_WRITE: return true;
case PLUGIN_EVENT_OUT: return true;
case PLUGIN_WEBFORM_SHOW_CONFIG: return false;
case PLUGIN_SERIAL_IN: return true;
case PLUGIN_UDP_IN: return true;
case PLUGIN_CLOCK_IN: return false;
case PLUGIN_TIMER_IN: return true;
case PLUGIN_FIFTY_PER_SECOND: return true;
case PLUGIN_SET_CONFIG: return false;
case PLUGIN_GET_DEVICEGPIONAMES: return false;
case PLUGIN_EXIT: return false;
case PLUGIN_GET_CONFIG: return false;
case PLUGIN_UNCONDITIONAL_POLL: return false;
case PLUGIN_REQUEST: return true;
}
return false;
}
String getCPluginCFunctionName(int function) {
switch (function) {
case CPLUGIN_PROTOCOL_ADD: return F("CPLUGIN_PROTOCOL_ADD");
case CPLUGIN_PROTOCOL_TEMPLATE: return F("CPLUGIN_PROTOCOL_TEMPLATE");
case CPLUGIN_PROTOCOL_SEND: return F("CPLUGIN_PROTOCOL_SEND");
case CPLUGIN_PROTOCOL_RECV: return F("CPLUGIN_PROTOCOL_RECV");
case CPLUGIN_GET_DEVICENAME: return F("CPLUGIN_GET_DEVICENAME");
case CPLUGIN_WEBFORM_SAVE: return F("CPLUGIN_WEBFORM_SAVE");
case CPLUGIN_WEBFORM_LOAD: return F("CPLUGIN_WEBFORM_LOAD");
case CPLUGIN_GET_PROTOCOL_DISPLAY_NAME: return F("CPLUGIN_GET_PROTOCOL_DISPLAY_NAME");
case CPLUGIN_TASK_CHANGE_NOTIFICATION: return F("CPLUGIN_TASK_CHANGE_NOTIFICATION");
case CPLUGIN_INIT: return F("CPLUGIN_INIT");
case CPLUGIN_UDP_IN: return F("CPLUGIN_UDP_IN");
}
return getUnknownString();
}
bool mustLogCFunction(int function) {
switch (function) {
case CPLUGIN_PROTOCOL_ADD: return false;
case CPLUGIN_PROTOCOL_TEMPLATE: return false;
case CPLUGIN_PROTOCOL_SEND: return true;
case CPLUGIN_PROTOCOL_RECV: return true;
case CPLUGIN_GET_DEVICENAME: return false;
case CPLUGIN_WEBFORM_SAVE: return false;
case CPLUGIN_WEBFORM_LOAD: return false;
case CPLUGIN_GET_PROTOCOL_DISPLAY_NAME: return false;
case CPLUGIN_TASK_CHANGE_NOTIFICATION: return false;
case CPLUGIN_INIT: return false;
case CPLUGIN_UDP_IN: return true;
}
return false;
}
String getMiscStatsName(int stat) {
switch (stat) {
case LOADFILE_STATS: return F("Load File");
case SAVEFILE_STATS: return F("Save File");
case LOOP_STATS: return F("Loop");
case PLUGIN_CALL_50PS: return F("Plugin call 50 p/s");
case PLUGIN_CALL_10PS: return F("Plugin call 10 p/s");
case PLUGIN_CALL_10PSU: return F("Plugin call 10 p/s U");
case PLUGIN_CALL_1PS: return F("Plugin call 1 p/s");
case SENSOR_SEND_TASK: return F("SensorSendTask()");
case SEND_DATA_STATS: return F("sendData()");
case COMPUTE_FORMULA_STATS: return F("Compute formula");
case PROC_SYS_TIMER: return F("proc_system_timer()");
case SET_NEW_TIMER: return F("setNewTimerAt()");
case TIME_DIFF_COMPUTE: return F("timeDiff()");
case MQTT_DELAY_QUEUE: return F("Delay queue MQTT");
case TRY_CONNECT_HOST_TCP: return F("try_connect_host() (TCP)");
case TRY_CONNECT_HOST_UDP: return F("try_connect_host() (UDP)");
case HOST_BY_NAME_STATS: return F("hostByName()");
case CONNECT_CLIENT_STATS: return F("connectClient()");
case LOAD_CUSTOM_TASK_STATS: return F("LoadCustomTaskSettings()");
case WIFI_ISCONNECTED_STATS: return F("WiFi.isConnected()");
case WIFI_NOTCONNECTED_STATS: return F("WiFi.isConnected() (fail)");
case LOAD_TASK_SETTINGS: return F("LoadTaskSettings()");
case TRY_OPEN_FILE: return F("TryOpenFile()");
case SPIFFS_GC_SUCCESS: return F("SPIFFS GC success");
case SPIFFS_GC_FAIL: return F("SPIFFS GC fail");
case RULES_PROCESSING: return F("rulesProcessing()");
case GRAT_ARP_STATS: return F("sendGratuitousARP()");
case BACKGROUND_TASKS: return F("backgroundtasks()");
case HANDLE_SCHEDULER_IDLE: return F("handle_schedule() idle");
case HANDLE_SCHEDULER_TASK: return F("handle_schedule() task");
case C001_DELAY_QUEUE:
case C002_DELAY_QUEUE:
case C003_DELAY_QUEUE:
case C004_DELAY_QUEUE:
case C005_DELAY_QUEUE:
case C006_DELAY_QUEUE:
case C007_DELAY_QUEUE:
case C008_DELAY_QUEUE:
case C009_DELAY_QUEUE:
case C010_DELAY_QUEUE:
case C011_DELAY_QUEUE:
case C012_DELAY_QUEUE:
case C013_DELAY_QUEUE:
case C014_DELAY_QUEUE:
case C015_DELAY_QUEUE:
case C016_DELAY_QUEUE:
case C017_DELAY_QUEUE:
case C018_DELAY_QUEUE:
case C019_DELAY_QUEUE:
case C020_DELAY_QUEUE:
{
String result;
result.reserve(16);
result = F("Delay queue ");
result += get_formatted_Controller_number(static_cast<int>(stat - C001_DELAY_QUEUE + 1));
return result;
}
}
return getUnknownString();
}
+93
View File
@@ -0,0 +1,93 @@
#ifndef DATASTRUCTS_TIMINGSTATS_H
#define DATASTRUCTS_TIMINGSTATS_H
#include <Arduino.h>
#include <map>
/*********************************************************************************************\
* TimingStats
\*********************************************************************************************/
#define LOADFILE_STATS 0
#define SAVEFILE_STATS 1
#define LOOP_STATS 2
#define PLUGIN_CALL_50PS 3
#define PLUGIN_CALL_10PS 4
#define PLUGIN_CALL_10PSU 5
#define PLUGIN_CALL_1PS 6
#define SENSOR_SEND_TASK 7
#define SEND_DATA_STATS 8
#define COMPUTE_FORMULA_STATS 9
#define PROC_SYS_TIMER 10
#define SET_NEW_TIMER 11
#define TIME_DIFF_COMPUTE 12
#define MQTT_DELAY_QUEUE 13
#define C001_DELAY_QUEUE 14
#define C002_DELAY_QUEUE 15
#define C003_DELAY_QUEUE 16
#define C004_DELAY_QUEUE 17
#define C005_DELAY_QUEUE 18
#define C006_DELAY_QUEUE 19
#define C007_DELAY_QUEUE 20
#define C008_DELAY_QUEUE 21
#define C009_DELAY_QUEUE 22
#define C010_DELAY_QUEUE 23
#define C011_DELAY_QUEUE 24
#define C012_DELAY_QUEUE 25
#define C013_DELAY_QUEUE 26
#define C014_DELAY_QUEUE 27
#define C015_DELAY_QUEUE 28
#define C016_DELAY_QUEUE 29
#define C017_DELAY_QUEUE 30
#define C018_DELAY_QUEUE 31
#define C019_DELAY_QUEUE 32
#define C020_DELAY_QUEUE 33
#define TRY_CONNECT_HOST_TCP 34
#define TRY_CONNECT_HOST_UDP 35
#define HOST_BY_NAME_STATS 36
#define CONNECT_CLIENT_STATS 37
#define LOAD_CUSTOM_TASK_STATS 38
#define WIFI_ISCONNECTED_STATS 39
#define WIFI_NOTCONNECTED_STATS 40
#define LOAD_TASK_SETTINGS 41
#define TRY_OPEN_FILE 42
#define SPIFFS_GC_SUCCESS 43
#define SPIFFS_GC_FAIL 44
#define RULES_PROCESSING 45
#define GRAT_ARP_STATS 46
#define BACKGROUND_TASKS 47
#define HANDLE_SCHEDULER_IDLE 48
#define HANDLE_SCHEDULER_TASK 49
class TimingStats {
public:
TimingStats();
void add(unsigned long time);
void reset();
bool isEmpty() const;
float getAvg() const;
unsigned int getMinMax(unsigned long& minVal,
unsigned long& maxVal) const;
bool thresholdExceeded(unsigned long threshold) const;
private:
float _timeTotal;
unsigned int _count;
unsigned long _maxVal;
unsigned long _minVal;
};
String getPluginFunctionName(int function);
bool mustLogFunction(int function);
String getCPluginCFunctionName(int function);
bool mustLogCFunction(int function);
String getMiscStatsName(int stat);
#endif // DATASTRUCTS_TIMINGSTATS_H
+643
View File
@@ -0,0 +1,643 @@
#ifndef DELAY_QUEUE_ELEMENTS_H
#define DELAY_QUEUE_ELEMENTS_H
#include "DataStructs/ControllerSettingsStruct.h"
#include "ESPEasy_fdwdecl.h"
// These element classes should be defined as class, to be used as template.
/*********************************************************************************************\
* MQTT_queue_element for all MQTT base controllers
\*********************************************************************************************/
class MQTT_queue_element {
public:
MQTT_queue_element() : controller_idx(0), _retained(false) {}
MQTT_queue_element(int ctrl_idx,
const String& topic, const String& payload, boolean retained) :
controller_idx(ctrl_idx), _topic(topic), _payload(payload), _retained(retained)
{}
size_t getSize() const {
return sizeof(this) + _topic.length() + _payload.length();
}
int controller_idx;
String _topic;
String _payload;
boolean _retained;
};
/*********************************************************************************************\
* Simple queue element, only storing controller index and some String
\*********************************************************************************************/
class simple_queue_element_string_only {
public:
simple_queue_element_string_only() : controller_idx(0) {}
simple_queue_element_string_only(int ctrl_idx, const String& req) :
controller_idx(ctrl_idx), txt(req) {}
size_t getSize() const {
return sizeof(this) + txt.length();
}
int controller_idx;
String txt;
};
//#ifdef USES_C001
/*********************************************************************************************\
* C001_queue_element for queueing requests for C001.
\*********************************************************************************************/
#define C001_queue_element simple_queue_element_string_only
//#endif //USES_C001
//#ifdef USES_C003
/*********************************************************************************************\
* C003_queue_element for queueing requests for C003 Nodo Telnet.
\*********************************************************************************************/
#define C003_queue_element simple_queue_element_string_only
//#endif //USES_C003
//#ifdef USES_C004
/*********************************************************************************************\
* C004_queue_element for queueing requests for C004 ThingSpeak.
* Typical use case for Thingspeak is to only send values every N seconds/minutes.
* So we just store everything needed to recreate the event when the time is ready.
\*********************************************************************************************/
class C004_queue_element {
public:
C004_queue_element() : controller_idx(0), TaskIndex(0), idx(0), sensorType(0) {}
C004_queue_element(const struct EventStruct *event) :
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
idx(event->idx),
sensorType(event->sensorType) {
if (sensorType == SENSOR_TYPE_STRING) {
txt = event->String2;
}
}
size_t getSize() const {
return sizeof(this) + txt.length();
}
int controller_idx;
byte TaskIndex;
int idx;
byte sensorType;
String txt;
};
//#endif //USES_C004
//#ifdef USES_C007
/*********************************************************************************************\
* C007_queue_element for queueing requests for C007 Emoncms
\*********************************************************************************************/
class C007_queue_element {
public:
C007_queue_element() : controller_idx(0), TaskIndex(0), idx(0), sensorType(0) {}
C007_queue_element(const struct EventStruct *event) :
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
idx(event->idx),
sensorType(event->sensorType) {}
size_t getSize() const {
return sizeof(this);
}
int controller_idx;
byte TaskIndex;
int idx;
byte sensorType;
};
//#endif //USES_C007
/*********************************************************************************************\
* Base class for controllers that only send a single value per request and thus needs to
* keep track of the number of values already sent.
\*********************************************************************************************/
class queue_element_single_value_base {
public:
queue_element_single_value_base() : controller_idx(0), TaskIndex(0), idx(0), valuesSent(0) {}
queue_element_single_value_base(const struct EventStruct *event, byte value_count) :
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
idx(event->idx),
valuesSent(0),
valueCount(value_count) {}
bool checkDone(bool succesfull) const {
if (succesfull) { ++valuesSent; }
return valuesSent >= valueCount || valuesSent >= VARS_PER_TASK;
}
size_t getSize() const {
size_t total = sizeof(this);
for (int i = 0; i < VARS_PER_TASK; ++i) {
total += txt[i].length();
}
return total;
}
String txt[VARS_PER_TASK];
int controller_idx;
byte TaskIndex;
int idx;
mutable byte valuesSent; // Value must be set by const function checkDone()
byte valueCount;
};
//#ifdef USES_C008
/*********************************************************************************************\
* C008_queue_element for queueing requests for 008: Generic HTTP
* Using queue_element_single_value_base
\*********************************************************************************************/
#define C008_queue_element queue_element_single_value_base
//#endif //USES_C008
//#ifdef USES_C009
/*********************************************************************************************\
* C009_queue_element for queueing requests for C009: FHEM HTTP.
\*********************************************************************************************/
class C009_queue_element {
public:
C009_queue_element() : controller_idx(0), TaskIndex(0), idx(0), sensorType(0) {}
C009_queue_element(const struct EventStruct *event) :
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
idx(event->idx),
sensorType(event->sensorType) {}
size_t getSize() const {
size_t total = sizeof(this);
for (int i = 0; i < VARS_PER_TASK; ++i) {
total += txt[i].length();
}
return total;
}
String txt[VARS_PER_TASK];
int controller_idx;
byte TaskIndex;
int idx;
byte sensorType;
};
//#endif //USES_C009
//#ifdef USES_C010
/*********************************************************************************************\
* C010_queue_element for queueing requests for 010: Generic UDP
* Using queue_element_single_value_base
\*********************************************************************************************/
#define C010_queue_element queue_element_single_value_base
//#endif //USES_C010
//#ifdef USES_C011
/*********************************************************************************************\
* C011_queue_element for queueing requests for 011: Generic HTTP Advanced
\*********************************************************************************************/
#define C011_queue_element simple_queue_element_string_only
//#endif //USES_C011
//#ifdef USES_C012
/*********************************************************************************************\
* C012_queue_element for queueing requests for 012: Blynk
* Using queue_element_single_value_base
\*********************************************************************************************/
#define C012_queue_element queue_element_single_value_base
//#endif //USES_C012
//#ifdef USES_C015
/*********************************************************************************************\
* C015_queue_element for queueing requests for 015: Blynk
* Using queue_element_single_value_base
\*********************************************************************************************/
// #define C015_queue_element queue_element_single_value_base
class C015_queue_element {
public:
C015_queue_element() : controller_idx(0), TaskIndex(0), idx(0), valuesSent(0) {}
C015_queue_element(const struct EventStruct *event, byte value_count) :
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
idx(event->idx),
valuesSent(0),
valueCount(value_count) {}
bool checkDone(bool succesfull) const {
if (succesfull) { ++valuesSent; }
return valuesSent >= valueCount || valuesSent >= VARS_PER_TASK;
}
size_t getSize() const {
size_t total = sizeof(this);
for (int i = 0; i < VARS_PER_TASK; ++i) {
total += txt[i].length();
}
return total;
}
String txt[VARS_PER_TASK];
int vPin[VARS_PER_TASK] = {0};
int controller_idx;
byte TaskIndex;
int idx;
mutable byte valuesSent; // Value must be set by const function checkDone()
byte valueCount;
};
//#endif //USES_C015
//#ifdef USES_C016
/*********************************************************************************************\
* C016_queue_element for queueing requests for C016: Cached HTTP.
\*********************************************************************************************/
class C016_queue_element {
public:
C016_queue_element() : timestamp(0), controller_idx(0), TaskIndex(0), sensorType(0) {}
C016_queue_element(const struct EventStruct *event, byte value_count, unsigned long unixTime) :
timestamp(unixTime),
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
sensorType(event->sensorType),
valueCount(value_count)
{
const byte BaseVarIndex = TaskIndex * VARS_PER_TASK;
for (byte i = 0; i < VARS_PER_TASK; ++i) {
if (i < value_count) {
values[i] = UserVar[BaseVarIndex + i];
} else {
values[i] = 0.0;
}
}
}
size_t getSize() const {
return sizeof(this);
}
float values[VARS_PER_TASK];
unsigned long timestamp; // Unix timestamp
byte controller_idx;
byte TaskIndex;
byte sensorType;
byte valueCount;
};
//#endif //USES_C016
//#ifdef USES_C017
/*********************************************************************************************\
* C017_queue_element for queueing requests for C017: Zabbix Trapper Protocol.
\*********************************************************************************************/
class C017_queue_element {
public:
C017_queue_element() : controller_idx(0), TaskIndex(0), idx(0), sensorType(0) {}
C017_queue_element(const struct EventStruct *event) :
controller_idx(event->ControllerIndex),
TaskIndex(event->TaskIndex),
idx(event->idx),
sensorType(event->sensorType) {}
size_t getSize() const {
size_t total = sizeof(this);
for (int i = 0; i < VARS_PER_TASK; ++i) {
total += txt[i].length();
}
return total;
}
String txt[VARS_PER_TASK];
int controller_idx;
byte TaskIndex;
int idx;
byte sensorType;
};
//#endif //USES_C017
//#ifdef USES_C018
/*********************************************************************************************\
* C018_queue_element for queueing requests for C018: TTN/RN2483
\*********************************************************************************************/
#ifdef USES_PACKED_RAW_DATA
String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount);
#endif // USES_PACKED_RAW_DATA
class C018_queue_element {
public:
C018_queue_element() {}
C018_queue_element(struct EventStruct *event, uint8_t sampleSetCount) :
controller_idx(event->ControllerIndex)
{
#ifdef USES_PACKED_RAW_DATA
packed = getPackedFromPlugin(event, sampleSetCount);
#endif // USES_PACKED_RAW_DATA
}
size_t getSize() const {
return sizeof(this) + packed.length();
}
int controller_idx = 0;
String packed;
};
//#endif //USES_C018
/*********************************************************************************************\
* ControllerDelayHandlerStruct
\*********************************************************************************************/
template<class T>
struct ControllerDelayHandlerStruct {
ControllerDelayHandlerStruct() :
lastSend(0),
minTimeBetweenMessages(CONTROLLER_DELAY_QUEUE_DELAY_DFLT),
max_queue_depth(CONTROLLER_DELAY_QUEUE_DEPTH_DFLT),
attempt(0),
max_retries(CONTROLLER_DELAY_QUEUE_RETRY_DFLT),
delete_oldest(false),
must_check_reply(false) {}
void configureControllerSettings(const ControllerSettingsStruct& settings) {
minTimeBetweenMessages = settings.MinimalTimeBetweenMessages;
max_queue_depth = settings.MaxQueueDepth;
max_retries = settings.MaxRetry;
delete_oldest = settings.DeleteOldest;
must_check_reply = settings.MustCheckReply;
// Set some sound limits when not configured
if (max_queue_depth == 0) { max_queue_depth = CONTROLLER_DELAY_QUEUE_DEPTH_DFLT; }
if (max_retries == 0) { max_retries = CONTROLLER_DELAY_QUEUE_RETRY_DFLT; }
if (minTimeBetweenMessages == 0) { minTimeBetweenMessages = CONTROLLER_DELAY_QUEUE_DELAY_DFLT; }
// No less than 10 msec between messages.
if (minTimeBetweenMessages < 10) { minTimeBetweenMessages = 10; }
}
bool queueFull(const T& element) const {
if (sendQueue.size() >= max_queue_depth) { return true; }
// Number of elements is not exceeding the limit, check memory
int freeHeap = ESP.getFreeHeap();
if (freeHeap > 5000) { return false; // Memory is not an issue.
}
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = "Controller-";
log += element.controller_idx + 1;
log += " : Memory used: ";
log += getQueueMemorySize();
log += " bytes ";
log += sendQueue.size();
log += " items ";
log += freeHeap;
log += " free";
addLog(LOG_LEVEL_DEBUG, log);
}
#endif // ifndef BUILD_NO_DEBUG
return true;
}
// Try to add to the queue, if permitted by "delete_oldest"
// Return false when no item was added.
bool addToQueue(const T& element) {
if (delete_oldest) {
// Force add to the queue.
// If max buffer is reached, the oldest in the queue (first to be served) will be removed.
while (queueFull(element)) {
sendQueue.pop_front();
}
sendQueue.emplace_back(element);
return true;
}
if (!queueFull(element)) {
sendQueue.emplace_back(element);
return true;
}
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = get_formatted_Controller_number(element.controller_idx);
log += " : queue full";
addLog(LOG_LEVEL_DEBUG, log);
}
#endif // ifndef BUILD_NO_DEBUG
return false;
}
// Get the next element.
// Remove front element when max_retries is reached.
T* getNext() {
if (sendQueue.empty()) { return NULL; }
if (attempt > max_retries) {
sendQueue.pop_front();
attempt = 0;
if (sendQueue.empty()) { return NULL; }
}
return &sendQueue.front();
}
// Mark as processed and return time to schedule for next process.
// Return 0 when nothing to process.
// @param remove_from_queue indicates whether the elements should be removed from the queue.
unsigned long markProcessed(bool remove_from_queue) {
if (sendQueue.empty()) { return 0; }
if (remove_from_queue) {
sendQueue.pop_front();
attempt = 0;
} else {
++attempt;
}
lastSend = millis();
return getNextScheduleTime();
}
unsigned long getNextScheduleTime() const {
if (sendQueue.empty()) { return 0; }
unsigned long nextTime = lastSend + minTimeBetweenMessages;
if (timePassedSince(nextTime) > 0) {
nextTime = millis();
}
if (nextTime == 0) { nextTime = 1; // Just to make sure it will be executed
}
return nextTime;
}
size_t getQueueMemorySize() const {
size_t totalSize = 0;
for (auto it = sendQueue.begin(); it != sendQueue.end(); ++it) {
totalSize += it->getSize();
}
return totalSize;
}
std::list<T> sendQueue;
unsigned long lastSend;
unsigned int minTimeBetweenMessages;
byte max_queue_depth;
byte attempt;
byte max_retries;
bool delete_oldest;
bool must_check_reply;
};
ControllerDelayHandlerStruct<MQTT_queue_element> MQTTDelayHandler;
// Uncrustify must not be used on macros, so turn it off.
// *INDENT-OFF*
// This macro defines the code needed to create the 'process_c##NNN####M##_delay_queue()'
// function and all needed objects and forward declarations.
// It is a macro to prevent common typo errors.
// This function will perform the (re)scheduling and mark if it is processed (and can be removed)
// The controller itself must implement the 'do_process_c004_delay_queue' function to actually
// send the data.
// Its return value must state whether it can be marked 'Processed'.
// N.B. some controllers only can send one value per iteration, so a returned "false" can mean it
// was still successful. The controller should keep track of the last value sent
// in the element stored in the queue.
#define DEFINE_Cxxx_DELAY_QUEUE_MACRO(NNN, M) \
ControllerDelayHandlerStruct<C##NNN####M##_queue_element>C##NNN####M##_DelayHandler; \
bool do_process_c##NNN####M##_delay_queue(int controller_number, \
const C##NNN####M##_queue_element & element, \
ControllerSettingsStruct & ControllerSettings); \
void process_c##NNN####M##_delay_queue() { \
C##NNN####M##_queue_element *element(C##NNN####M##_DelayHandler.getNext()); \
if (element == NULL) return; \
MakeControllerSettings (ControllerSettings); \
LoadControllerSettings(element->controller_idx, ControllerSettings); \
C##NNN####M##_DelayHandler.configureControllerSettings(ControllerSettings); \
if (!WiFiConnected(10)) { \
scheduleNextDelayQueue(TIMER_C##NNN####M##_DELAY_QUEUE, C##NNN####M##_DelayHandler.getNextScheduleTime()); \
return; \
} \
START_TIMER; \
C##NNN####M##_DelayHandler.markProcessed(do_process_c##NNN####M##_delay_queue(M, *element, ControllerSettings)); \
STOP_TIMER(C##NNN####M##_DELAY_QUEUE); \
scheduleNextDelayQueue(TIMER_C##NNN####M##_DELAY_QUEUE, C##NNN####M##_DelayHandler.getNextScheduleTime()); \
}
// Define the function wrappers to handle the calling to Cxxx_DelayHandler etc.
// If someone knows how to add leading zeros in macros, please be my guest :)
#ifdef USES_C001
DEFINE_Cxxx_DELAY_QUEUE_MACRO(00, 1)
#endif // ifdef USES_C001
#ifdef USES_C003
DEFINE_Cxxx_DELAY_QUEUE_MACRO(00, 3)
#endif // ifdef USES_C003
#ifdef USES_C004
DEFINE_Cxxx_DELAY_QUEUE_MACRO(00, 4)
#endif // ifdef USES_C004
#ifdef USES_C007
DEFINE_Cxxx_DELAY_QUEUE_MACRO(00, 7)
#endif // ifdef USES_C007
#ifdef USES_C008
DEFINE_Cxxx_DELAY_QUEUE_MACRO(00, 8)
#endif // ifdef USES_C008
#ifdef USES_C009
DEFINE_Cxxx_DELAY_QUEUE_MACRO(00, 9)
#endif // ifdef USES_C009
#ifdef USES_C010
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 10)
#endif // ifdef USES_C010
#ifdef USES_C011
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 11)
#endif // ifdef USES_C011
#ifdef USES_C012
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 12)
#endif // ifdef USES_C012
/*
#ifdef USES_C013
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 13)
#endif
*/
/*
#ifdef USES_C014
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 14)
#endif
*/
#ifdef USES_C015
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 15)
#endif // ifdef USES_C015
#ifdef USES_C016
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 16)
#endif // ifdef USES_C016
#ifdef USES_C017
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 17)
#endif // ifdef USES_C017
#ifdef USES_C018
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 18)
#endif
/*
#ifdef USES_C019
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 19)
#endif
*/
/*
#ifdef USES_C020
DEFINE_Cxxx_DELAY_QUEUE_MACRO(0, 20)
#endif
*/
// When extending this, also extend in Scheduler.ino:
// void process_interval_timer(unsigned long id, unsigned long lasttimer)
// Uncrustify must not be used on macros, but we're now done, so turn Uncrustify on again.
// *INDENT-ON*
#endif // DELAY_QUEUE_ELEMENTS_H
+58 -1051
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -82,8 +82,25 @@
// SHT1X temperature/humidity sensors
// Ser2Net server
// Define globals before plugin sets to allow a personal override of the selected plugins
#include "ESPEasy-Globals.h"
// Must be included after all the defines, since it is using TASKS_MAX
#include "_Plugin_Helper.h"
// Plugin helper needs the defined controller sets, thus include after 'define_plugin_sets.h'
#include "_CPlugin_Helper.h"
#include "DelayQueueElements.h"
// Get functions to give access to global defined variables.
// These are needed to get direct access to global defined variables, since they cannot be defined in .h files and included more than once.
SettingsStruct& getSettings() { return Settings; }
SecurityStruct& getSecuritySettings() { return SecuritySettings; }
CRCStruct& getCRCValues() { return CRCValues; }
unsigned long& getConnectionFailures() { return connectionFailures; }
byte& getHighestActiveLogLevel() { return highest_active_log_level; }
int getPluginId_from_TaskIndex(byte taskIndex) { return Task_id_to_Plugin_id[taskIndex]; }
#ifdef USES_BLYNK
@@ -121,6 +138,9 @@ void sw_watchdog_callback(void *arg)
++sw_watchdog_callback_count;
}
/*********************************************************************************************\
* SETUP
\*********************************************************************************************/
+25
View File
@@ -403,6 +403,31 @@ byte disableNotification(byte bootFailedCount) {
return bootFailedCount;
}
#define DAT_TASKS_DISTANCE 2048 // DAT_TASKS_SIZE + DAT_TASKS_CUSTOM_SIZE
#define DAT_TASKS_SIZE 1024
#define DAT_TASKS_CUSTOM_OFFSET 1024 // Equal to DAT_TASKS_SIZE
#define DAT_TASKS_CUSTOM_SIZE 1024
#define DAT_CUSTOM_CONTROLLER_SIZE 1024
#define DAT_CONTROLLER_SIZE 1024
#define DAT_NOTIFICATION_SIZE 1024
#define DAT_BASIC_SETTINGS_SIZE 4096
#if defined(ESP8266)
#define DAT_OFFSET_TASKS 4096 // each task = 2k, (1024 basic + 1024 bytes custom), 12 max
#define DAT_OFFSET_CONTROLLER 28672 // each controller = 1k, 4 max
#define DAT_OFFSET_CUSTOM_CONTROLLER 32768 // each custom controller config = 1k, 4 max.
#define CONFIG_FILE_SIZE 65536
#endif
#if defined(ESP32)
#define DAT_OFFSET_CONTROLLER 8192 // each controller = 1k, 4 max
#define DAT_OFFSET_CUSTOM_CONTROLLER 12288 // each custom controller config = 1k, 4 max.
#define DAT_OFFSET_TASKS 32768 // each task = 2k, (1024 basic + 1024 bytes custom), 32 max
#define CONFIG_FILE_SIZE 131072
#endif
/********************************************************************************************\
Offsets in settings files
\*********************************************************************************************/
+54
View File
@@ -0,0 +1,54 @@
#ifndef ESP_EASY_LOG_H
#define ESP_EASY_LOG_H
#include "ESPEasy_common.h"
#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_DEBUG_MORE 4
#define LOG_LEVEL_DEBUG_DEV 9 // use for testing/debugging only, not for regular use
#define LOG_LEVEL_NRELEMENTS 5 // Update this and getLogLevelDisplayString() when new log levels are added
#define LOG_TO_SERIAL 1
#define LOG_TO_SYSLOG 2
#define LOG_TO_WEBLOG 3
#define LOG_TO_SDCARD 4
/********************************************************************************************\
Logging
\*********************************************************************************************/
String getLogLevelDisplayString(int logLevel);
String getLogLevelDisplayStringFromIndex(byte index, int& logLevel);
void addToLog(byte loglevel, const String& string);
void addToLog(byte logLevel, const __FlashStringHelper* flashString);
void disableSerialLog();
void setLogLevelFor(byte destination, byte logLevel);
void updateLogLevelCache();
bool loglevelActiveFor(byte logLevel);
byte getSerialLogLevel();
byte getWebLogLevel();
bool loglevelActiveFor(byte destination, byte logLevel);
bool loglevelActive(byte logLevel, byte logLevelSettings);
void addToLog(byte logLevel, const char *line);
// Do this in a template to prevent casting to String when not needed.
#define addLog(L,S) if (loglevelActiveFor(L)) { addToLog(L,S); }
#endif // ESP_EASY_LOG_H
+185
View File
@@ -0,0 +1,185 @@
#include "ESPEasy_Log.h"
/********************************************************************************************\
Init critical variables for logging (important during initial factory reset stuff )
\*********************************************************************************************/
void initLog()
{
//make sure addLog doesnt do any stuff before initalisation of Settings is complete.
Settings.UseSerial=true;
Settings.SyslogFacility=0;
setLogLevelFor(LOG_TO_SYSLOG, 0);
setLogLevelFor(LOG_TO_SERIAL, 2); //logging during initialisation
setLogLevelFor(LOG_TO_WEBLOG, 2);
setLogLevelFor(LOG_TO_SDCARD, 0);
}
/********************************************************************************************\
Logging
\*********************************************************************************************/
String getLogLevelDisplayString(int logLevel) {
switch (logLevel) {
case LOG_LEVEL_NONE: return F("None");
case LOG_LEVEL_ERROR: return F("Error");
case LOG_LEVEL_INFO: return F("Info");
case LOG_LEVEL_DEBUG: return F("Debug");
case LOG_LEVEL_DEBUG_MORE: return F("Debug More");
case LOG_LEVEL_DEBUG_DEV: return F("Debug dev");
default:
return "";
}
}
String getLogLevelDisplayStringFromIndex(byte index, int& logLevel) {
switch (index) {
case 0: logLevel = LOG_LEVEL_ERROR; break;
case 1: logLevel = LOG_LEVEL_INFO; break;
case 2: logLevel = LOG_LEVEL_DEBUG; break;
case 3: logLevel = LOG_LEVEL_DEBUG_MORE; break;
case 4: logLevel = LOG_LEVEL_DEBUG_DEV; break;
default: logLevel = -1; return "";
}
return getLogLevelDisplayString(logLevel);
}
void addToLog(byte loglevel, const String& string)
{
addToLog(loglevel, string.c_str());
}
void addToLog(byte logLevel, const __FlashStringHelper* flashString)
{
checkRAM(F("addToLog"));
String s(flashString);
addToLog(logLevel, s.c_str());
}
void disableSerialLog() {
log_to_serial_disabled = true;
setLogLevelFor(LOG_TO_SERIAL, 0);
}
void setLogLevelFor(byte destination, byte logLevel) {
switch (destination) {
case LOG_TO_SERIAL:
if (!log_to_serial_disabled || logLevel == 0)
Settings.SerialLogLevel = logLevel; break;
case LOG_TO_SYSLOG: Settings.SyslogLevel = logLevel; break;
case LOG_TO_WEBLOG: Settings.WebLogLevel = logLevel; break;
case LOG_TO_SDCARD: Settings.SDLogLevel = logLevel; break;
default:
break;
}
updateLogLevelCache();
}
void updateLogLevelCache() {
byte max_lvl = 0;
if (log_to_serial_disabled) {
if (Settings.UseSerial) {
Serial.setDebugOutput(false);
}
} else {
max_lvl = _max(max_lvl, Settings.SerialLogLevel);
#ifndef BUILD_NO_DEBUG
if (Settings.UseSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) {
Serial.setDebugOutput(true);
}
#endif
}
max_lvl = _max(max_lvl, Settings.SyslogLevel);
if (Logging.logActiveRead()) {
max_lvl = _max(max_lvl, Settings.WebLogLevel);
}
#ifdef FEATURE_SD
max_lvl = _max(max_lvl, Settings.SDLogLevel);
#endif
highest_active_log_level = max_lvl;
}
bool loglevelActiveFor(byte logLevel) {
return loglevelActive(logLevel, highest_active_log_level);
}
byte getSerialLogLevel() {
if (log_to_serial_disabled || !Settings.UseSerial) return 0;
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED){
if (Settings.SerialLogLevel < LOG_LEVEL_INFO) {
return LOG_LEVEL_INFO;
}
}
return Settings.SerialLogLevel;
}
byte getWebLogLevel() {
byte logLevelSettings = 0;
if (Logging.logActiveRead()) {
logLevelSettings = Settings.WebLogLevel;
} else {
if (Settings.WebLogLevel != 0) {
updateLogLevelCache();
}
}
return logLevelSettings;
}
bool loglevelActiveFor(byte destination, byte logLevel) {
byte logLevelSettings = 0;
switch (destination) {
case LOG_TO_SERIAL: {
logLevelSettings = getSerialLogLevel();
break;
}
case LOG_TO_SYSLOG: {
logLevelSettings = Settings.SyslogLevel;
break;
}
case LOG_TO_WEBLOG: {
logLevelSettings = getWebLogLevel();
break;
}
case LOG_TO_SDCARD: {
#ifdef FEATURE_SD
logLevelSettings = Settings.SDLogLevel;
#endif
break;
}
default:
return false;
}
return loglevelActive(logLevel, logLevelSettings);
}
bool loglevelActive(byte logLevel, byte logLevelSettings) {
return (logLevel <= logLevelSettings);
}
void addToLog(byte logLevel, const char *line)
{
if (loglevelActiveFor(LOG_TO_SERIAL, logLevel)) {
addToSerialBuffer(String(millis()).c_str());
addToSerialBuffer(" : ");
addToSerialBuffer(line);
addNewlineToSerialBuffer();
}
if (loglevelActiveFor(LOG_TO_SYSLOG, logLevel)) {
syslog(logLevel, line);
}
if (loglevelActiveFor(LOG_TO_WEBLOG, logLevel)) {
Logging.add(logLevel, line);
}
#ifdef FEATURE_SD
if (loglevelActiveFor(LOG_TO_SDCARD, logLevel)) {
File logFile = SD.open("log.dat", FILE_WRITE);
if (logFile)
logFile.println(line);
logFile.close();
}
#endif
}
+31
View File
@@ -0,0 +1,31 @@
#ifndef ESPEASY_BUILD_INFO_H
#define ESPEASY_BUILD_INFO_H
// ********************************************************************************
// DO NOT CHANGE ANYTHING BELOW THIS LINE
// ********************************************************************************
#define ESP_PROJECT_PID 2016110801L
#if defined(ESP8266)
# define VERSION 2 // config file version (not ESPEasy version). increase if you make incompatible changes to
// config system.
#endif // if defined(ESP8266)
#if defined(ESP32)
# define VERSION 3 // Change in config.dat mapping needs a full reset
#endif // if defined(ESP32)
#define BUILD 20103 // git version 2.1.03
#if defined(ESP8266)
# define BUILD_NOTES " - Mega"
#endif // if defined(ESP8266)
#if defined(ESP32)
# define BUILD_NOTES " - Mega32"
#endif // if defined(ESP32)
#ifndef BUILD_GIT
# define BUILD_GIT "(custom)"
#endif // ifndef BUILD_GIT
#endif // ESPEASY_BUILD_INFO_H
+3
View File
@@ -1,5 +1,8 @@
#include "ESPEasy_common.h"
String getUnknownString() { return F("Unknown"); }
/*********************************************************************************************\
Bitwise operators
\*********************************************************************************************/
+2
View File
@@ -15,6 +15,8 @@ namespace std
#define ZERO_TERMINATE(S) S[sizeof(S) - 1] = 0
String getUnknownString();
/*********************************************************************************************\
Bitwise operators
\*********************************************************************************************/
+18 -15
View File
@@ -20,22 +20,35 @@
#include <FS.h>
struct SettingsStruct;
struct SecurityStruct;
struct CRCStruct;
// Forward declaration to give access to global member variables
SettingsStruct& getSettings();
SecurityStruct& getSecuritySettings();
CRCStruct& getCRCValues();
unsigned long& getConnectionFailures();
byte& getHighestActiveLogLevel();
int getPluginId_from_TaskIndex(byte taskIndex);
// Forward declaration
struct ControllerSettingsStruct;
String getUnknownString();
void scheduleNextDelayQueue(unsigned long id, unsigned long nextTime);
String LoadControllerSettings(int ControllerIndex, ControllerSettingsStruct& controller_settings);
String get_formatted_Controller_number(int controller_index);
bool loglevelActiveFor(byte logLevel);
void addToLog(byte loglevel, const String& string);
void addToLog(byte logLevel, const __FlashStringHelper* flashString);
void statusLED(boolean traffic);
void backgroundtasks();
uint32_t getCurrentFreeStack();
uint32_t getFreeStackWatermark();
bool canYield();
boolean timeOutReached(unsigned long timer);
long timePassedSince(unsigned long timestamp);
long usecPassedSince(unsigned long timestamp);
void serialHelper_getGpioNames(struct EventStruct *event, bool rxOptional=false, bool txOptional=false);
fs::File tryOpenFile(const String& fname, const String& mode);
@@ -76,17 +89,6 @@ void rulesProcessing(String& event);
void setIntervalTimer(unsigned long id);
byte getProtocolIndex(byte Number);
#ifdef USES_PACKED_RAW_DATA
// Forward declarations PackedData related functions
typedef uint32_t PackedData_enum;
uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset);
void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, byte *data, uint8_t& cursor);
String LoRa_base16Encode(byte *data, size_t size);
String LoRa_addInt(uint64_t value, PackedData_enum datatype);
static String LoRa_addFloat(float value, PackedData_enum datatype);
//String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount);
#endif // USES_PACKED_RAW_DATA
#ifdef USES_MQTT
//void runPeriodicalMQTT();
//void updateMQTTclient_connected();
@@ -99,4 +101,5 @@ bool MQTTCheck(int controller_idx);
void schedule_all_tasks_using_MQTT_controller();
#endif
#endif // ESPEASY_FWD_DECL_H
+91
View File
@@ -0,0 +1,91 @@
#include "ESPEasy_packed_raw_data.h"
uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset) {
offset = 0;
factor = 1;
if (dtype > 0x1000 && dtype < 0x12FF) {
const uint8_t exponent = dtype & 0xF;
switch(exponent) {
case 0: factor = 1; break;
case 1: factor = 1e1; break;
case 2: factor = 1e2; break;
case 3: factor = 1e3; break;
case 4: factor = 1e4; break;
case 5: factor = 1e5; break;
case 6: factor = 1e6; break;
}
const uint8_t size = (dtype >> 8) & 0xF;
return size;
}
switch (dtype) {
case PackedData_pluginid: factor = 1; return 1;
case PackedData_latLng: factor = 46600; return 3; // 2^23 / 180
case PackedData_hdop: factor = 10; return 1;
case PackedData_altitude: factor = 4; offset = 1000; return 2; // -1000 .. 15383.75 meter
case PackedData_vcc: factor = 41.83; offset = 1; return 1; // -1 .. 5.12V
case PackedData_pct_8: factor = 2.56; return 1; // 0 .. 100%
default:
break;
}
// Unknown type
factor = 1;
return 0;
}
void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, byte *data, uint8_t& cursor) {
// Clip values to upper limit
const uint64_t upperlimit = (1 << (8*byteSize)) - 1;
if (value > upperlimit) { value = upperlimit; }
for (uint8_t x = 0; x < byteSize; x++) {
byte next = 0;
if (sizeof(value) > x) {
next = static_cast<byte>((value >> (x * 8)) & 0xFF);
}
data[cursor] = next;
++cursor;
}
}
void LoRa_intToBytes(int64_t value, uint8_t byteSize, byte *data, uint8_t& cursor) {
// Clip values to lower limit
const int64_t lowerlimit = (1 << ((8*byteSize) - 1)) * -1;
if (value < lowerlimit) { value = lowerlimit; }
if (value < 0) {
value += (1 << (8*byteSize));
}
LoRa_uintToBytes(value, byteSize, data, cursor);
}
String LoRa_base16Encode(byte *data, size_t size) {
String output;
output.reserve(size * 2);
char buffer[3];
for (unsigned i=0; i<size; i++)
{
sprintf(buffer, "%02X", data[i]);
output += buffer[0];
output += buffer[1];
}
return output;
}
String LoRa_addInt(uint64_t value, PackedData_enum datatype) {
float factor, offset;
uint8_t byteSize = getPackedDataTypeSize(datatype, factor, offset);
byte data[4] = {0};
uint8_t cursor = 0;
LoRa_uintToBytes((value + offset) * factor, byteSize, &data[0], cursor);
return LoRa_base16Encode(data, cursor);
}
String LoRa_addFloat(float value, PackedData_enum datatype) {
float factor, offset;
uint8_t byteSize = getPackedDataTypeSize(datatype, factor, offset);
byte data[4] = {0};
uint8_t cursor = 0;
LoRa_intToBytes((value + offset) * factor, byteSize, &data[0], cursor);
return LoRa_base16Encode(data, cursor);
}
+83
View File
@@ -0,0 +1,83 @@
#ifndef ESPEASY_PACKED_RAW_DATA_H
#define ESPEASY_PACKED_RAW_DATA_H
#include "ESPEasy_common.h"
// Data types used in packed encoder.
// p_uint16_1e2 means it is a 16 bit unsigned int, but multiplied by 100 first.
// This allows to store 2 decimals of a floating point value in 8 bits, ranging from 0.00 ... 2.55
// For example p_int24_1e6 is a 24-bit signed value, ideal to store a GPS coordinate
// with 6 decimals using only 3 bytes instead of 4 a normal float would use.
//
// PackedData_uintX_1eY = 0x11XY (X= #bytes, Y=exponent)
// PackedData_intX_1eY = 0x12XY (X= #bytes, Y=exponent)
typedef uint32_t PackedData_enum;
#define PackedData_uint8 0x1110
#define PackedData_uint16 0x1120
#define PackedData_uint24 0x1130
#define PackedData_uint32 0x1140
#define PackedData_uint8_1e3 0x1113
#define PackedData_uint8_1e2 0x1112
#define PackedData_uint8_1e1 0x1111
#define PackedData_uint16_1e5 0x1125
#define PackedData_uint16_1e4 0x1124
#define PackedData_uint16_1e3 0x1123
#define PackedData_uint16_1e2 0x1122
#define PackedData_uint16_1e1 0x1121
#define PackedData_uint24_1e6 0x1136
#define PackedData_uint24_1e5 0x1135
#define PackedData_uint24_1e4 0x1134
#define PackedData_uint24_1e3 0x1133
#define PackedData_uint24_1e2 0x1132
#define PackedData_uint24_1e1 0x1131
#define PackedData_uint32_1e6 0x1146
#define PackedData_uint32_1e5 0x1145
#define PackedData_uint32_1e4 0x1144
#define PackedData_uint32_1e3 0x1143
#define PackedData_uint32_1e2 0x1142
#define PackedData_uint32_1e1 0x1141
#define PackedData_int8 0x1210
#define PackedData_int16 0x1220
#define PackedData_int24 0x1230
#define PackedData_int32 0x1240
#define PackedData_int8_1e3 0x1213
#define PackedData_int8_1e2 0x1212
#define PackedData_int8_1e1 0x1211
#define PackedData_int16_1e5 0x1225
#define PackedData_int16_1e4 0x1224
#define PackedData_int16_1e3 0x1223
#define PackedData_int16_1e2 0x1222
#define PackedData_int16_1e1 0x1221
#define PackedData_int24_1e6 0x1236
#define PackedData_int24_1e5 0x1235
#define PackedData_int24_1e4 0x1234
#define PackedData_int24_1e3 0x1233
#define PackedData_int24_1e2 0x1232
#define PackedData_int24_1e1 0x1231
#define PackedData_int32_1e6 0x1246
#define PackedData_int32_1e5 0x1245
#define PackedData_int32_1e4 0x1244
#define PackedData_int32_1e3 0x1243
#define PackedData_int32_1e2 0x1242
#define PackedData_int32_1e1 0x1241
#define PackedData_pluginid 1
#define PackedData_latLng 2
#define PackedData_hdop 3
#define PackedData_altitude 4
#define PackedData_vcc 5
#define PackedData_pct_8 6
uint8_t getPackedDataTypeSize(PackedData_enum dtype, float& factor, float& offset);
void LoRa_uintToBytes(uint64_t value, uint8_t byteSize, byte *data, uint8_t& cursor);
void LoRa_intToBytes(int64_t value, uint8_t byteSize, byte *data, uint8_t& cursor);
String LoRa_base16Encode(byte *data, size_t size);
String LoRa_addInt(uint64_t value, PackedData_enum datatype);
String LoRa_addFloat(float value, PackedData_enum datatype);
#endif // ESPEASY_PACKED_RAW_DATA_H
+81
View File
@@ -0,0 +1,81 @@
#ifndef ESPEASY_PLUGIN_DEFS_H
#define ESPEASY_PLUGIN_DEFS_H
// ********************************************************************************
// Plugin (Task) function calls
// ********************************************************************************
#define PLUGIN_INIT_ALL 1
#define PLUGIN_INIT 2
#define PLUGIN_READ 3 // This call can yield new data (when success = true) and then send to controllers
#define PLUGIN_ONCE_A_SECOND 4 // Called once a second
#define PLUGIN_TEN_PER_SECOND 5 // Called 10x per second (typical for checking new data instead of waiting)
#define PLUGIN_DEVICE_ADD 6 // Called at boot for letting a plugin adding itself to list of available plugins/devices
#define PLUGIN_EVENTLIST_ADD 7
#define PLUGIN_WEBFORM_SAVE 8 // Call from web interface to save settings
#define PLUGIN_WEBFORM_LOAD 9 // Call from web interface for presenting settings and status of plugin
#define PLUGIN_WEBFORM_SHOW_VALUES 10 // Call from devices overview page to format values in HTML
#define PLUGIN_GET_DEVICENAME 11
#define PLUGIN_GET_DEVICEVALUENAMES 12
#define PLUGIN_WRITE 13
#define PLUGIN_EVENT_OUT 14
#define PLUGIN_WEBFORM_SHOW_CONFIG 15
#define PLUGIN_SERIAL_IN 16
#define PLUGIN_UDP_IN 17
#define PLUGIN_CLOCK_IN 18
#define PLUGIN_TIMER_IN 19
#define PLUGIN_FIFTY_PER_SECOND 20
#define PLUGIN_SET_CONFIG 21
#define PLUGIN_GET_DEVICEGPIONAMES 22
#define PLUGIN_EXIT 23
#define PLUGIN_GET_CONFIG 24
#define PLUGIN_UNCONDITIONAL_POLL 25
#define PLUGIN_REQUEST 26
#define PLUGIN_TIME_CHANGE 27
#define PLUGIN_MONITOR 28
#define PLUGIN_SET_DEFAULTS 29
#define PLUGIN_GET_PACKED_RAW_DATA 30 // Return all data in a compact binary format specific for that plugin.
// Needs USES_PACKED_RAW_DATA
// ********************************************************************************
// CPlugin (Controller) function calls
// ********************************************************************************
// Make sure the CPLUGIN_* does not overlap PLUGIN_*
#define CPLUGIN_PROTOCOL_ADD 41 // Called at boot for letting a controller adding itself to list of available controllers
#define CPLUGIN_PROTOCOL_TEMPLATE 42
#define CPLUGIN_PROTOCOL_SEND 43
#define CPLUGIN_PROTOCOL_RECV 44
#define CPLUGIN_GET_DEVICENAME 45
#define CPLUGIN_WEBFORM_SAVE 46
#define CPLUGIN_WEBFORM_LOAD 47
#define CPLUGIN_GET_PROTOCOL_DISPLAY_NAME 48
#define CPLUGIN_TASK_CHANGE_NOTIFICATION 49
#define CPLUGIN_INIT 50
#define CPLUGIN_UDP_IN 51
#define CPLUGIN_FLUSH 52 // Force offloading data stored in buffers, called before sleep/reboot
// new messages for autodiscover controller plugins (experimental) i.e. C014
#define CPLUGIN_GOT_CONNECTED 53 // call after connected to mqtt server to publich device autodicover features
#define CPLUGIN_GOT_INVALID 54 // should be called before major changes i.e. changing the device name to clean up data on the controller. !ToDo
#define CPLUGIN_INTERVAL 55 // call every interval loop
#define CPLUGIN_ACKNOWLEDGE 56 // call for sending acknowledges !ToDo done by direct function call in PluginCall() for now.
#define CPLUGIN_WEBFORM_SHOW_HOST_CONFIG 57 // Used for showing host information for the controller.
// ********************************************************************************
// NPlugin (Notification) function calls
// ********************************************************************************
#define NPLUGIN_PROTOCOL_ADD 1
#define NPLUGIN_GET_DEVICENAME 2
#define NPLUGIN_WEBFORM_SAVE 3
#define NPLUGIN_WEBFORM_LOAD 4
#define NPLUGIN_WRITE 5
#define NPLUGIN_NOTIFY 6
#define NPLUGIN_NOT_FOUND 255
#endif // ESPEASY_PLUGIN_DEFS_H
-182
View File
@@ -2,7 +2,6 @@
ESPEasy specific strings
\*********************************************************************************************/
String getUnknownString() { return F("Unknown"); }
String getNodeTypeDisplayString(byte nodeType) {
switch (nodeType)
@@ -1400,187 +1399,6 @@ float timeStringToSeconds(String tBuf) {
return sec;
}
/********************************************************************************************\
Init critical variables for logging (important during initial factory reset stuff )
\*********************************************************************************************/
void initLog()
{
//make sure addLog doesnt do any stuff before initalisation of Settings is complete.
Settings.UseSerial=true;
Settings.SyslogFacility=0;
setLogLevelFor(LOG_TO_SYSLOG, 0);
setLogLevelFor(LOG_TO_SERIAL, 2); //logging during initialisation
setLogLevelFor(LOG_TO_WEBLOG, 2);
setLogLevelFor(LOG_TO_SDCARD, 0);
}
/********************************************************************************************\
Logging
\*********************************************************************************************/
String getLogLevelDisplayString(int logLevel) {
switch (logLevel) {
case LOG_LEVEL_NONE: return F("None");
case LOG_LEVEL_ERROR: return F("Error");
case LOG_LEVEL_INFO: return F("Info");
case LOG_LEVEL_DEBUG: return F("Debug");
case LOG_LEVEL_DEBUG_MORE: return F("Debug More");
case LOG_LEVEL_DEBUG_DEV: return F("Debug dev");
default:
return "";
}
}
String getLogLevelDisplayStringFromIndex(byte index, int& logLevel) {
switch (index) {
case 0: logLevel = LOG_LEVEL_ERROR; break;
case 1: logLevel = LOG_LEVEL_INFO; break;
case 2: logLevel = LOG_LEVEL_DEBUG; break;
case 3: logLevel = LOG_LEVEL_DEBUG_MORE; break;
case 4: logLevel = LOG_LEVEL_DEBUG_DEV; break;
default: logLevel = -1; return "";
}
return getLogLevelDisplayString(logLevel);
}
void addToLog(byte loglevel, const String& string)
{
addToLog(loglevel, string.c_str());
}
void addToLog(byte logLevel, const __FlashStringHelper* flashString)
{
checkRAM(F("addToLog"));
String s(flashString);
addToLog(logLevel, s.c_str());
}
void disableSerialLog() {
log_to_serial_disabled = true;
setLogLevelFor(LOG_TO_SERIAL, 0);
}
void setLogLevelFor(byte destination, byte logLevel) {
switch (destination) {
case LOG_TO_SERIAL:
if (!log_to_serial_disabled || logLevel == 0)
Settings.SerialLogLevel = logLevel; break;
case LOG_TO_SYSLOG: Settings.SyslogLevel = logLevel; break;
case LOG_TO_WEBLOG: Settings.WebLogLevel = logLevel; break;
case LOG_TO_SDCARD: Settings.SDLogLevel = logLevel; break;
default:
break;
}
updateLogLevelCache();
}
void updateLogLevelCache() {
byte max_lvl = 0;
if (log_to_serial_disabled) {
if (Settings.UseSerial) {
Serial.setDebugOutput(false);
}
} else {
max_lvl = _max(max_lvl, Settings.SerialLogLevel);
#ifndef BUILD_NO_DEBUG
if (Settings.UseSerial && Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) {
Serial.setDebugOutput(true);
}
#endif
}
max_lvl = _max(max_lvl, Settings.SyslogLevel);
if (Logging.logActiveRead()) {
max_lvl = _max(max_lvl, Settings.WebLogLevel);
}
#ifdef FEATURE_SD
max_lvl = _max(max_lvl, Settings.SDLogLevel);
#endif
highest_active_log_level = max_lvl;
}
bool loglevelActiveFor(byte logLevel) {
return loglevelActive(logLevel, highest_active_log_level);
}
byte getSerialLogLevel() {
if (log_to_serial_disabled || !Settings.UseSerial) return 0;
if (wifiStatus != ESPEASY_WIFI_SERVICES_INITIALIZED){
if (Settings.SerialLogLevel < LOG_LEVEL_INFO) {
return LOG_LEVEL_INFO;
}
}
return Settings.SerialLogLevel;
}
byte getWebLogLevel() {
byte logLevelSettings = 0;
if (Logging.logActiveRead()) {
logLevelSettings = Settings.WebLogLevel;
} else {
if (Settings.WebLogLevel != 0) {
updateLogLevelCache();
}
}
return logLevelSettings;
}
boolean loglevelActiveFor(byte destination, byte logLevel) {
byte logLevelSettings = 0;
switch (destination) {
case LOG_TO_SERIAL: {
logLevelSettings = getSerialLogLevel();
break;
}
case LOG_TO_SYSLOG: {
logLevelSettings = Settings.SyslogLevel;
break;
}
case LOG_TO_WEBLOG: {
logLevelSettings = getWebLogLevel();
break;
}
case LOG_TO_SDCARD: {
#ifdef FEATURE_SD
logLevelSettings = Settings.SDLogLevel;
#endif
break;
}
default:
return false;
}
return loglevelActive(logLevel, logLevelSettings);
}
boolean loglevelActive(byte logLevel, byte logLevelSettings) {
return (logLevel <= logLevelSettings);
}
void addToLog(byte logLevel, const char *line)
{
if (loglevelActiveFor(LOG_TO_SERIAL, logLevel)) {
addToSerialBuffer(String(millis()).c_str());
addToSerialBuffer(" : ");
addToSerialBuffer(line);
addNewlineToSerialBuffer();
}
if (loglevelActiveFor(LOG_TO_SYSLOG, logLevel)) {
syslog(logLevel, line);
}
if (loglevelActiveFor(LOG_TO_WEBLOG, logLevel)) {
Logging.add(logLevel, line);
}
#ifdef FEATURE_SD
if (loglevelActiveFor(LOG_TO_SDCARD, logLevel)) {
File logFile = SD.open("log.dat", FILE_WRITE);
if (logFile)
logFile.println(line);
logFile.close();
}
#endif
}
/********************************************************************************************\
+1 -1
View File
@@ -334,7 +334,7 @@ void process_interval_timer(unsigned long id, unsigned long lasttimer) {
#endif
*/
// When extending this, also extend in _CPlugin_Helper.h
// When extending this, also extend in DelayQueueElements.h
// Look for DEFINE_Cxxx_DELAY_QUEUE_MACRO
}
}
+422
View File
@@ -0,0 +1,422 @@
#include "_CPlugin_Helper.h"
#include "ESPEasy_fdwdecl.h"
#include "ESPEasy_Log.h"
#include "ESPEasy_buildinfo.h"
#include "DataStructs/SecurityStruct.h"
#include "DataStructs/CRCStruct.h"
#include "DataStructs/SettingsStruct.h"
#include "DataStructs/ControllerSettingsStruct.h"
#include "DataStructs/ESPEasyLimits.h"
#include "DataStructs/TimingStats.h"
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <base64.h>
bool safeReadStringUntil(Stream & input,
String & str,
char terminator,
unsigned int maxSize,
unsigned int timeout)
{
int c;
const unsigned long start = millis();
const unsigned long timer = start + timeout;
unsigned long backgroundtasks_timer = start + 10;
str = "";
do {
// read character
if (input.available()) {
c = input.read();
if (c >= 0) {
// found terminator, we're ok
if (c == terminator) {
return true;
}
// found character, add to string
else {
str += char(c);
// string at max size?
if (str.length() >= maxSize) {
addLog(LOG_LEVEL_ERROR, F("Not enough bufferspace to read all input data!"));
return false;
}
}
}
// We must run the backgroundtasks every now and then.
if (timeOutReached(backgroundtasks_timer)) {
backgroundtasks_timer += 10;
backgroundtasks();
} else {
delay(0);
}
} else {
delay(0);
}
} while (!timeOutReached(timer));
addLog(LOG_LEVEL_ERROR, F("Timeout while reading input data!"));
return false;
}
bool valid_controller_number(int controller_number) {
if (controller_number < 0) { return false; }
return true;
// return getProtocolIndex(controller_number) <= protocolCount;
}
String get_formatted_Controller_number(int controller_number) {
if (!valid_controller_number(controller_number)) {
return F("C---");
}
String result = F("C");
if (controller_number < 100) { result += '0'; }
if (controller_number < 10) { result += '0'; }
result += controller_number;
return result;
}
String get_auth_header(const String& user, const String& pass) {
String authHeader = "";
if (user.length() != 0 && pass.length() != 0) {
base64 encoder;
String auth = user;
auth += ":";
auth += pass;
authHeader = F("Authorization: Basic ");
authHeader += encoder.encode(auth);
authHeader += F(" \r\n");
}
return authHeader;
}
String get_auth_header(int controller_index) {
String authHeader = "";
if (controller_index < CONTROLLER_MAX) {
if ((getSecuritySettings().ControllerUser[controller_index][0] != 0) &&
(getSecuritySettings().ControllerPassword[controller_index][0] != 0))
{
authHeader = get_auth_header(
String(getSecuritySettings().ControllerUser[controller_index]),
String(getSecuritySettings().ControllerPassword[controller_index]));
}
} else {
addLog(LOG_LEVEL_ERROR, F("Invalid controller index"));
}
return authHeader;
}
String get_user_agent_request_header_field() {
static unsigned int agent_size = 20;
String request;
request.reserve(agent_size);
request = F("User-Agent: ");
request += F("ESP Easy/");
request += BUILD;
request += '/';
request += String(getCRCValues().compileDate);
request += ' ';
request += String(getCRCValues().compileTime);
request += "\r\n";
agent_size = request.length();
return request;
}
String do_create_http_request(
const String& hostportString,
const String& method, const String& uri,
const String& auth_header, const String& additional_options,
int content_length) {
int estimated_size = hostportString.length() + method.length()
+ uri.length() + auth_header.length()
+ additional_options.length()
+ 42;
if (content_length >= 0) { estimated_size += 25; }
String request;
request.reserve(estimated_size);
request += method;
request += ' ';
if (!uri.startsWith("/")) { request += '/'; }
request += uri;
request += F(" HTTP/1.1");
request += "\r\n";
if (content_length >= 0) {
request += F("Content-Length: ");
request += content_length;
request += "\r\n";
}
request += F("Host: ");
request += hostportString;
request += "\r\n";
request += auth_header;
request += additional_options;
request += get_user_agent_request_header_field();
request += F("Connection: close\r\n");
request += "\r\n";
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG, request);
#endif // ifndef BUILD_NO_DEBUG
return request;
}
String do_create_http_request(
const String& hostportString,
const String& method, const String& uri) {
return do_create_http_request(hostportString, method, uri,
"", // auth_header
"", // additional_options
-1 // content_length
);
}
String do_create_http_request(
int controller_number, ControllerSettingsStruct& ControllerSettings,
const String& method, const String& uri,
int content_length) {
const bool defaultport = ControllerSettings.Port == 0 || ControllerSettings.Port == 80;
return do_create_http_request(
defaultport ? ControllerSettings.getHost() : ControllerSettings.getHostPortString(),
method,
uri,
"", // auth_header
"", // additional_options
content_length);
}
String create_http_request_auth(
int controller_number, int controller_index, ControllerSettingsStruct& ControllerSettings,
const String& method, const String& uri,
int content_length) {
const bool defaultport = ControllerSettings.Port == 0 || ControllerSettings.Port == 80;
return do_create_http_request(
defaultport ? ControllerSettings.getHost() : ControllerSettings.getHostPortString(),
method,
uri,
get_auth_header(controller_index),
"", // additional_options
content_length);
}
String create_http_get_request(int controller_number, ControllerSettingsStruct& ControllerSettings,
const String& uri) {
return do_create_http_request(controller_number, ControllerSettings, F("GET"), uri, -1);
}
String create_http_request_auth(int controller_number, int controller_index, ControllerSettingsStruct& ControllerSettings,
const String& method, const String& uri) {
return create_http_request_auth(controller_number, controller_index, ControllerSettings, method, uri, -1);
}
#ifndef BUILD_NO_DEBUG
void log_connecting_to(const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings) {
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = prefix;
log += get_formatted_Controller_number(controller_number);
log += F(" connecting to ");
log += ControllerSettings.getHostPortString();
addLog(LOG_LEVEL_DEBUG, log);
}
}
#endif // ifndef BUILD_NO_DEBUG
void log_connecting_fail(const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = prefix;
log += get_formatted_Controller_number(controller_number);
log += F(" connection failed (");
log += getConnectionFailures();
log += F("/");
log += getSettings().ConnectionFailuresThreshold;
log += F(")");
addLog(LOG_LEVEL_ERROR, log);
}
}
bool count_connection_results(bool success, const String& prefix, int controller_number, ControllerSettingsStruct& ControllerSettings) {
if (!success)
{
getConnectionFailures()++;
log_connecting_fail(prefix, controller_number, ControllerSettings);
return false;
}
statusLED(true);
if (getConnectionFailures()) {
getConnectionFailures()--;
}
return true;
}
bool try_connect_host(int controller_number, WiFiUDP& client, ControllerSettingsStruct& ControllerSettings) {
//START_TIMER; // FIXME TD-er Timingstats macros currently not callable from .cpp file
if (!WiFiConnected()) return false;
client.setTimeout(ControllerSettings.ClientTimeout);
#ifndef BUILD_NO_DEBUG
log_connecting_to(F("UDP : "), controller_number, ControllerSettings);
#endif // ifndef BUILD_NO_DEBUG
bool success = ControllerSettings.beginPacket(client) != 0;
const bool result = count_connection_results(
success,
F("UDP : "), controller_number, ControllerSettings);
//STOP_TIMER(TRY_CONNECT_HOST_UDP);
return result;
}
bool try_connect_host(int controller_number, WiFiClient& client, ControllerSettingsStruct& ControllerSettings) {
//START_TIMER; // FIXME TD-er Timingstats macros currently not callable from .cpp file
if (!WiFiConnected()) return false;
// Use WiFiClient class to create TCP connections
client.setTimeout(ControllerSettings.ClientTimeout);
#ifndef BUILD_NO_DEBUG
log_connecting_to(F("HTTP : "), controller_number, ControllerSettings);
#endif // ifndef BUILD_NO_DEBUG
bool success = ControllerSettings.connectToHost(client);
const bool result = count_connection_results(
success,
F("HTTP : "), controller_number, ControllerSettings);
//STOP_TIMER(TRY_CONNECT_HOST_TCP);
return result;
}
// Use "client.available() || client.connected()" to read all lines from slow servers.
// See: https://github.com/esp8266/Arduino/pull/5113
// https://github.com/esp8266/Arduino/pull/1829
bool client_available(WiFiClient& client) {
delay(0);
return client.available() || client.connected();
}
bool send_via_http(const String& logIdentifier, WiFiClient& client, const String& postStr, bool must_check_reply) {
bool success = !must_check_reply;
// This will send the request to the server
byte written = client.print(postStr);
// as of 2018/11/01 the print function only returns one byte (upd to 256 chars sent). However if the string sent can be longer than this
// therefore we calculate modulo 256.
// see discussion here https://github.com/letscontrolit/ESPEasy/pull/1979
// and implementation here
// https://github.com/esp8266/Arduino/blob/561426c0c77e9d05708f2c4bf2a956d3552a3706/libraries/ESP8266WiFi/src/include/ClientContext.h#L437-L467
// this needs to be adjusted if the WiFiClient.print method changes.
if (written != (postStr.length() % 256)) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = F("HTTP : ");
log += logIdentifier;
log += F(" Error: could not write to client (");
log += written;
log += "/";
log += postStr.length();
log += ")";
addLog(LOG_LEVEL_ERROR, log);
}
success = false;
}
#ifndef BUILD_NO_DEBUG
else {
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("HTTP : ");
log += logIdentifier;
log += F(" written to client (");
log += written;
log += "/";
log += postStr.length();
log += ")";
addLog(LOG_LEVEL_DEBUG, log);
}
}
#endif // ifndef BUILD_NO_DEBUG
if (must_check_reply) {
unsigned long timer = millis() + 200;
while (!client_available(client)) {
if (timeOutReached(timer)) { return false; }
delay(1);
}
// Read all the lines of the reply from server and print them to Serial
while (client_available(client) && !success) {
// String line = client.readStringUntil('\n');
String line;
safeReadStringUntil(client, line, '\n');
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG_MORE)) {
if (line.length() > 80) {
addLog(LOG_LEVEL_DEBUG_MORE, line.substring(0, 80));
} else {
addLog(LOG_LEVEL_DEBUG_MORE, line);
}
}
#endif // ifndef BUILD_NO_DEBUG
if (line.startsWith(F("HTTP/1.1 2")))
{
success = true;
// Leave this debug info in the build, regardless of the
// BUILD_NO_DEBUG flags.
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("HTTP : ");
log += logIdentifier;
log += F(" Success! ");
log += line;
addLog(LOG_LEVEL_DEBUG, log);
}
} else if (line.startsWith(F("HTTP/1.1 4"))) {
if (loglevelActiveFor(LOG_LEVEL_ERROR)) {
String log = F("HTTP : ");
log += logIdentifier;
log += F(" Error: ");
log += line;
addLog(LOG_LEVEL_ERROR, log);
}
#ifndef BUILD_NO_DEBUG
addLog(LOG_LEVEL_DEBUG_MORE, postStr);
#endif // ifndef BUILD_NO_DEBUG
}
delay(0);
}
}
#ifndef BUILD_NO_DEBUG
if (loglevelActiveFor(LOG_LEVEL_DEBUG)) {
String log = F("HTTP : ");
log += logIdentifier;
log += F(" closing connection");
addLog(LOG_LEVEL_DEBUG, log);
}
#endif // ifndef BUILD_NO_DEBUG
client.flush();
client.stop();
return success;
}
bool send_via_http(int controller_number, WiFiClient& client, const String& postStr, bool must_check_reply) {
return send_via_http(get_formatted_Controller_number(controller_number), client, postStr, must_check_reply);
}
+24 -996
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -4,6 +4,7 @@
#if defined(USES_PACKED_RAW_DATA)
#include "ESPEasy_packed_raw_data.h"
String getPackedFromPlugin(struct EventStruct *event, uint8_t sampleSetCount)
+2
View File
@@ -4,6 +4,8 @@
//#######################################################################################################
#include "ESPEasy_packed_raw_data.h"
#define PLUGIN_026
#define PLUGIN_ID_026 26
#define PLUGIN_NAME_026 "Generic - System Info"
+1
View File
@@ -12,6 +12,7 @@
#include <ESPeasySerial.h>
#include <TinyGPS++.h>
#include "ESPEasy_packed_raw_data.h"
#define PLUGIN_082
#define PLUGIN_ID_082 82
+103
View File
@@ -0,0 +1,103 @@
#include "_Plugin_Helper.h"
#include "ESPEasy_common.h"
#include "ESPEasy_fdwdecl.h"
#include "DataStructs/ESPEasyLimits.h"
#include "DataStructs/SettingsStruct.h"
PluginTaskData_base *Plugin_task_data[TASKS_MAX] = { NULL, };
String PCONFIG_LABEL(int n) {
if (n < PLUGIN_CONFIGVAR_MAX) {
String result = F("pconf_");
result += n;
return result;
}
return F("error");
}
void resetPluginTaskData() {
for (byte i = 0; i < TASKS_MAX; ++i) {
Plugin_task_data[i] = nullptr;
}
}
void clearPluginTaskData(byte taskIndex) {
if (taskIndex < TASKS_MAX) {
if (Plugin_task_data[taskIndex] != nullptr) {
delete Plugin_task_data[taskIndex];
Plugin_task_data[taskIndex] = nullptr;
}
}
}
void initPluginTaskData(byte taskIndex, PluginTaskData_base *data) {
clearPluginTaskData(taskIndex);
if ((taskIndex < TASKS_MAX) && getSettings().TaskDeviceEnabled[taskIndex]) {
Plugin_task_data[taskIndex] = data;
Plugin_task_data[taskIndex]->_taskdata_plugin_id = getPluginId_from_TaskIndex(taskIndex);
}
}
PluginTaskData_base* getPluginTaskData(byte taskIndex) {
if (taskIndex >= TASKS_MAX) {
return nullptr;
}
if ((Plugin_task_data[taskIndex] != nullptr) && (Plugin_task_data[taskIndex]->_taskdata_plugin_id == getPluginId_from_TaskIndex(taskIndex))) {
return Plugin_task_data[taskIndex];
}
return nullptr;
}
bool pluginTaskData_initialized(byte taskIndex) {
// FIXME TD-er: Must check for type also.
if (taskIndex < TASKS_MAX) {
return Plugin_task_data[taskIndex] != nullptr;
}
return false;
}
String getPluginCustomArgName(int varNr) {
String argName = F("plugin_custom_arg");
argName += varNr + 1;
return argName;
}
// Helper function to create formatted custom values for display in the devices overview page.
// When called from PLUGIN_WEBFORM_SHOW_VALUES, the last item should add a traling div_br class
// if the regular values should also be displayed.
// The call to PLUGIN_WEBFORM_SHOW_VALUES should only return success = true when no regular values should be displayed
// Note that the varNr of the custom values should not conflict with the existing variable numbers (e.g. start at VARS_PER_TASK)
String pluginWebformShowValue(byte taskIndex, byte varNr, const String& label, const String& value, bool addTrailingBreak) {
String result;
size_t length = 96 + label.length() + value.length();
String breakStr = F("<div class='div_br'></div>");
if (addTrailingBreak) {
length += breakStr.length();
}
result.reserve(length);
if (varNr > 0) {
result += breakStr;
}
result += F("<div class='div_l' id='valuename_");
result += String(taskIndex);
result += '_';
result += String(varNr);
result += "'>";
result += label;
result += F(":</div><div class='div_r' id='value_");
result += String(taskIndex);
result += '_';
result += String(varNr);
result += "'>";
result += value;
result += "</div>";
if (addTrailingBreak) {
result += breakStr;
}
return result;
}
+13 -83
View File
@@ -1,6 +1,9 @@
#ifndef PLUGIN_HELPER_H
#define PLUGIN_HELPER_H
#include "ESPEasy_common.h"
#include "DataStructs/ESPEasyLimits.h"
// Defines to make plugins more readable.
#ifndef PCONFIG
@@ -30,14 +33,7 @@
# define CONFIG_PORT (Settings.TaskDevicePort[event->TaskIndex])
#endif // ifndef CONFIG_PORT
String PCONFIG_LABEL(int n) {
if (n < PLUGIN_CONFIGVAR_MAX) {
String result = "pconf_";
result += n;
return result;
}
return "error";
}
String PCONFIG_LABEL(int n);
// ==============================================
// Data used by instances of plugins.
@@ -56,94 +52,28 @@ struct PluginTaskData_base {
int _taskdata_plugin_id = -1;
};
PluginTaskData_base *Plugin_task_data[TASKS_MAX] = { NULL, };
void resetPluginTaskData() {
for (byte i = 0; i < TASKS_MAX; ++i) {
Plugin_task_data[i] = nullptr;
}
}
void clearPluginTaskData(byte taskIndex) {
if (taskIndex < TASKS_MAX) {
if (Plugin_task_data[taskIndex] != nullptr) {
delete Plugin_task_data[taskIndex];
Plugin_task_data[taskIndex] = nullptr;
}
}
}
void resetPluginTaskData();
void initPluginTaskData(byte taskIndex, PluginTaskData_base *data) {
clearPluginTaskData(taskIndex);
void clearPluginTaskData(byte taskIndex);
if ((taskIndex < TASKS_MAX) && Settings.TaskDeviceEnabled[taskIndex]) {
Plugin_task_data[taskIndex] = data;
Plugin_task_data[taskIndex]->_taskdata_plugin_id = Task_id_to_Plugin_id[taskIndex];
}
}
void initPluginTaskData(byte taskIndex, PluginTaskData_base *data);
PluginTaskData_base* getPluginTaskData(byte taskIndex) {
if (taskIndex >= TASKS_MAX) {
return nullptr;
}
PluginTaskData_base* getPluginTaskData(byte taskIndex);
if ((Plugin_task_data[taskIndex] != nullptr) && (Plugin_task_data[taskIndex]->_taskdata_plugin_id == Task_id_to_Plugin_id[taskIndex])) {
return Plugin_task_data[taskIndex];
}
return nullptr;
}
bool pluginTaskData_initialized(byte taskIndex);
bool pluginTaskData_initialized(byte taskIndex) {
// FIXME TD-er: Must check for type also.
if (taskIndex < TASKS_MAX) {
return Plugin_task_data[taskIndex] != nullptr;
}
return false;
}
String getPluginCustomArgName(int varNr) {
String argName = F("plugin_custom_arg");
argName += varNr + 1;
return argName;
}
String getPluginCustomArgName(int varNr);
// Helper function to create formatted custom values for display in the devices overview page.
// When called from PLUGIN_WEBFORM_SHOW_VALUES, the last item should add a traling div_br class
// if the regular values should also be displayed.
// The call to PLUGIN_WEBFORM_SHOW_VALUES should only return success = true when no regular values should be displayed
// Note that the varNr of the custom values should not conflict with the existing variable numbers (e.g. start at VARS_PER_TASK)
String pluginWebformShowValue(byte taskIndex, byte varNr, const String& label, const String& value, bool addTrailingBreak) {
String result;
size_t length = 96 + label.length() + value.length();
String breakStr = F("<div class='div_br'></div>");
if (addTrailingBreak) {
length += breakStr.length();
}
result.reserve(length);
if (varNr > 0) {
result += breakStr;
}
result += F("<div class='div_l' id='valuename_");
result += String(taskIndex);
result += '_';
result += String(varNr);
result += "'>";
result += label;
result += F(":</div><div class='div_r' id='value_");
result += String(taskIndex);
result += '_';
result += String(varNr);
result += "'>";
result += value;
result += "</div>";
if (addTrailingBreak) {
result += breakStr;
}
return result;
}
String pluginWebformShowValue(byte taskIndex, byte varNr, const String& label, const String& value, bool addTrailingBreak = false);
String pluginWebformShowValue(byte taskIndex, byte varNr, const String& label, const String& value) {
return pluginWebformShowValue(taskIndex, varNr, label, value, false);
}
#endif // PLUGIN_HELPER_H