Compare commits

...
Author SHA1 Message Date
ESPEasy release bot 41341b46de automatically updated release notes for mega-20180801 2018-08-01 04:00:18 +02:00
Gijs NoorlanderandGitHub 3574517014 Merge pull request #1618 from TD-er/bugfix/storage_task_settings
[#1574] Stability improvements on ExtraTaskSettings
2018-07-31 20:31:21 +02:00
Edwin Eefting cca785e1f0 Power down PN532 after reading. Saves power and reduces interference with Wifi. 2018-07-31 16:53:32 +02:00
TD-er 4215e058d0 [#1306] Added %R% and %N% for literals \r and \n 2018-07-30 22:41:25 +02:00
TD-er 2f91fbe931 [#1379] Check for "forbidden" characters in names. 2018-07-29 21:59:27 +02:00
TD-er 90febfd46f [#882] Add checks on names in task setup
When saving a task, a warning or error is displayed (when appropriate) when the settings are saved.
2018-07-29 21:59:18 +02:00
TD-er ccc5b68111 [Storage] Simplify settings I/O error handling
Remove a lot of code duplication
2018-07-29 21:59:13 +02:00
TD-er 07f6b86138 [Storage] Split storage related functions to new file
Only moved the storage related functions from `Misc.ino` to the new `ESPEasyStorage.ino`
2018-07-29 21:59:08 +02:00
TD-er 7b2667feaa [compiler fix] Forgot to declare String 2018-07-29 21:59:02 +02:00
TD-er 48bd7b334d [FileHandling] Write some log indicating file operation
Add some log line indicating what setting is read of written.
2018-07-29 21:58:57 +02:00
TD-er 9dd4242590 [meminfodetail] Add command meminfodetail
This command `meminfodetail` does output the detailed structure of the settings stored.
See for an example:
https://github.com/letscontrolit/ESPEasy/issues/1574#issuecomment-408641424
2018-07-29 21:58:51 +02:00
TD-er ac8c29e9c5 [ExtraTaskSettings] Keep ExtraTaskSettings actualized for plugin calls 2018-07-29 21:58:45 +02:00
TD-er 387b0f68a8 [ExtraTaskSettings] Added extra clear functions and checks
Mainly reading and writing files / settings now perform a lot more checks.
2018-07-29 21:58:38 +02:00
TD-er fa130bf649 [ExtraTaskSettings] Added some comments & clarifications 2018-07-29 21:58:31 +02:00
19 changed files with 1087 additions and 739 deletions
+23
View File
@@ -1,3 +1,26 @@
-------------------------------------------------
Changes in release mega-20180801 (since mega-20180723)
-------------------------------------------------
Release date: Wed Aug 1 04:00:18 CEST 2018
Edwin Eefting (1):
Power down PN532 after reading. Saves power and reduces interference with Wifi.
TD-er (11):
[ExtraTaskSettings] Added some comments & clarifications
[ExtraTaskSettings] Added extra clear functions and checks
[ExtraTaskSettings] Keep ExtraTaskSettings actualized for plugin calls
[meminfodetail] Add command `meminfodetail`
[FileHandling] Write some log indicating file operation
[compiler fix] Forgot to declare String
[Storage] Split storage related functions to new file
[Storage] Simplify settings I/O error handling
[#882] Add checks on names in task setup
[#1379] Check for "forbidden" characters in names.
[#1306] Added %R% and %N% for literals \r and \n
-------------------------------------------------
Changes in release mega-20180723 (since mega-20180722)
-------------------------------------------------
+2 -1
View File
@@ -85,7 +85,8 @@ bool doExecuteCommand(const char * cmd, struct EventStruct *event, const char* l
}
case 'm': {
COMMAND_CASE("malloc" , Command_Malloc); // Diagnostic.h
COMMAND_CASE("meminfo" , Command_MenInfo); // Diagnostic.h
COMMAND_CASE("meminfo" , Command_MemInfo); // Diagnostic.h
COMMAND_CASE("meminfodetail" , Command_MemInfo_detail); // Diagnostic.h
COMMAND_CASE("messagedelay" , Command_MQTT_messageDelay); // MQTT.h
COMMAND_CASE("mqttretainflag" , Command_MQTT_Retain); // MQTT.h
break;
+35 -5
View File
@@ -38,20 +38,50 @@ bool Command_SerialFloat(struct EventStruct *event, const char* Line)
return success;
}
bool Command_MenInfo(struct EventStruct *event, const char* Line)
bool Command_MemInfo(struct EventStruct *event, const char* Line)
{
bool success = true;
Serial.print(F("SecurityStruct : "));
Serial.print(F("SecurityStruct | "));
Serial.println(sizeof(SecuritySettings));
Serial.print(F("SettingsStruct : "));
Serial.print(F("SettingsStruct | "));
Serial.println(sizeof(Settings));
Serial.print(F("ExtraTaskSettingsStruct: "));
Serial.print(F("ExtraTaskSettingsStruct| "));
Serial.println(sizeof(ExtraTaskSettings));
Serial.print(F("DeviceStruct: "));
Serial.print(F("DeviceStruct | "));
Serial.println(sizeof(Device));
return success;
}
bool Command_MemInfo_detail(struct EventStruct *event, const char* Line)
{
bool success = true;
Command_MemInfo(event, Line);
for (int st = 0; st < SettingsType_MAX; ++st) {
SettingsType settingsType = static_cast<SettingsType>(st);
int max_index, offset, max_size;
int struct_size = 0;
Serial.println();
Serial.print(getSettingsTypeString(settingsType));
Serial.println(F(" | start | end | max_size | struct_size"));
Serial.println(F("--- | --- | --- | --- | ---"));
getSettingsParameters(settingsType, 0, max_index, offset, max_size, struct_size);
for (int i = 0; i < max_index; ++i) {
getSettingsParameters(settingsType, i, offset, max_size);
Serial.print(i);
Serial.print('|');
Serial.print(offset);
Serial.print('|');
Serial.print(offset + max_size);
Serial.print('|');
Serial.print(max_size);
Serial.print('|');
Serial.println(struct_size);
}
}
return success;
}
bool Command_Background(struct EventStruct *event, const char* Line)
{
bool success = true;
+7 -6
View File
@@ -5,6 +5,7 @@
bool Command_Task_Clear(struct EventStruct *event, const char* Line)
{
bool success = true;
// Par1 is here for 1 ... TASKS_MAX
taskClear(event->Par1 - 1, true);
return success;
}
@@ -12,13 +13,13 @@ bool Command_Task_Clear(struct EventStruct *event, const char* Line)
bool Command_Task_ClearAll(struct EventStruct *event, const char* Line)
{
bool success = true;
for (byte t=0; t<TASKS_MAX; t++)
for (byte t = 0; t < TASKS_MAX; t++)
taskClear(t, false);
return success;
}
bool Command_Task_ValueSet(struct EventStruct *event, const char* Line)
{
{
bool success = true;
char TmpStr1[INPUT_COMMAND_SIZE];
if (GetArgv(Line, TmpStr1, 4))
@@ -29,14 +30,14 @@ bool Command_Task_ValueSet(struct EventStruct *event, const char* Line)
}
else
{
//TODO: Get Task description and var name
//TODO: Get Task description and var name
Serial.println(UserVar[(VARS_PER_TASK * (event->Par1 - 1)) + event->Par2 - 1]);
}
return success;
}
bool Command_Task_ValueSetAndRun(struct EventStruct *event, const char* Line)
{
{
bool success = true;
char TmpStr1[INPUT_COMMAND_SIZE];
if (GetArgv(Line, TmpStr1, 4))
@@ -50,7 +51,7 @@ bool Command_Task_ValueSetAndRun(struct EventStruct *event, const char* Line)
}
bool Command_Task_Run(struct EventStruct *event, const char* Line)
{
{
bool success = true;
SensorSendTask(event->Par1 - 1);
return success;
@@ -64,4 +65,4 @@ bool Command_Task_RemoteConfig(struct EventStruct *event, const char* Line)
return true;
}
#endif // COMMAND_TASKS_H
#endif // COMMAND_TASKS_H
+191 -66
View File
@@ -302,6 +302,7 @@
#define RULES_MAX_NESTING_LEVEL 3
#define RULESETS_MAX 4
#define RULES_BUFFER_SIZE 64
#define NAME_FORMULA_LENGTH_MAX 40
#define PIN_MODE_UNDEFINED 0
#define PIN_MODE_INPUT 1
@@ -344,8 +345,9 @@
#define BOOT_CAUSE_DEEP_SLEEP 2
#define BOOT_CAUSE_EXT_WD 10
#define DAT_TASKS_SIZE 2048
#define DAT_TASKS_CUSTOM_OFFSET 1024
#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
@@ -364,6 +366,30 @@
#define CONFIG_FILE_SIZE 131072
#endif
enum SettingsType {
TaskSettings_Type = 0,
CustomTaskSettings_Type,
ControllerSettings_Type,
CustomControllerSettings_Type,
NotificationSettings_Type,
SettingsType_MAX
};
bool getSettingsParameters(SettingsType settingsType, int index, int& offset, int& max_size);
String getSettingsTypeString(SettingsType settingsType) {
switch (settingsType) {
case TaskSettings_Type: return F("TaskSettings");
case CustomTaskSettings_Type: return F("CustomTaskSettings");
case ControllerSettings_Type: return F("ControllerSettings");
case CustomControllerSettings_Type: return F("CustomControllerSettings");
case NotificationSettings_Type: return F("NotificationSettings");
default:
break;
}
return String();
}
/*
To modify the stock configuration without changing this repo file :
- define USE_CUSTOM_H as a build flags. ie : export PLATFORMIO_BUILD_FLAGS="'-DUSE_CUSTOM_H'"
@@ -581,48 +607,94 @@ struct SecurityStruct
struct SettingsStruct
{
SettingsStruct() :
PID(0), Version(0), Build(0), IP_Octet(0), Unit(0), Delay(0),
Pin_i2c_sda(-1), Pin_i2c_scl(-1), Pin_status_led(-1), Pin_sd_cs(-1),
UDPPort(0), SyslogLevel(0), SerialLogLevel(0), WebLogLevel(0), SDLogLevel(0),
BaudRate(0), MessageDelay(0), deepSleep(0),
CustomCSS(false), DST(false), WDI2CAddress(0),
UseRules(false), UseSerial(false), UseSSDP(false), UseNTP(false),
WireClockStretchLimit(0), GlobalSync(false), ConnectionFailuresThreshold(0),
TimeZone(0), MQTTRetainFlag(false), InitSPI(false),
Pin_status_led_Inversed(false), deepSleepOnFail(false), UseValueLogger(false),
DST_Start(0), DST_End(0), UseRTOSMultitasking(false), Pin_Reset(-1),
SyslogFacility(DEFAULT_SYSLOG_FACILITY), StructSize(0), MQTTUseUnitNameAsClientId(0)
{
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
Protocol[i] = 0;
ControllerEnabled[i] = false;
for (byte task = 0; task < TASKS_MAX; ++task) {
TaskDeviceID[i][task] = 0;
TaskDeviceSendData[i][task] = false;
}
}
for (byte task = 0; task < TASKS_MAX; ++task) {
TaskDeviceNumber[task] = 0;
OLD_TaskDeviceID[task] = 0;
TaskDevicePin1PullUp[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
TaskDevicePluginConfig[task][cv] = 0;
}
TaskDevicePin1Inversed[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
TaskDevicePluginConfigFloat[task][cv] = 0.0;
}
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
TaskDevicePluginConfigLong[task][cv] = 0;
}
OLD_TaskDeviceSendData[task] = false;
TaskDeviceGlobalSync[task] = false;
TaskDeviceDataFeed[task] = 0;
TaskDeviceTimer[task] = 0;
TaskDeviceEnabled[task] = false;
}
SettingsStruct() {
clearAll();
}
void clearAll() {
PID = 0;
Version = 0;
Build = 0;
IP_Octet = 0;
Unit = 0;
Delay = 0;
Pin_i2c_sda = -1;
Pin_i2c_scl = -1;
Pin_status_led = -1;
Pin_sd_cs = -1;
UDPPort = 0;
SyslogLevel = 0;
SerialLogLevel = 0;
WebLogLevel = 0;
SDLogLevel = 0;
BaudRate = 0;
MessageDelay = 0;
deepSleep = 0;
CustomCSS = false;
DST = false;
WDI2CAddress = 0;
UseRules = false;
UseSerial = false;
UseSSDP = false;
UseNTP = false;
WireClockStretchLimit = 0;
GlobalSync = false;
ConnectionFailuresThreshold = 0;
TimeZone = 0;
MQTTRetainFlag = false;
InitSPI = false;
Pin_status_led_Inversed = false;
deepSleepOnFail = false;
UseValueLogger = false;
DST_Start = 0;
DST_End = 0;
UseRTOSMultitasking = false;
Pin_Reset = -1;
SyslogFacility = DEFAULT_SYSLOG_FACILITY;
StructSize = 0;
MQTTUseUnitNameAsClientId = 0;
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
Protocol[i] = 0;
ControllerEnabled[i] = false;
}
for (byte i = 0; i < NOTIFICATION_MAX; ++i) {
Notification[i] = 0;
NotificationEnabled[i] = false;
}
for (byte task = 0; task < TASKS_MAX; ++task) {
clearTask(task);
}
}
void clearTask(byte task) {
for (byte i = 0; i < CONTROLLER_MAX; ++i) {
TaskDeviceID[i][task] = 0;
TaskDeviceSendData[i][task] = false;
}
TaskDeviceNumber[task] = 0;
OLD_TaskDeviceID[task] = 0;
TaskDevicePin1[task] = -1;
TaskDevicePin2[task] = -1;
TaskDevicePin3[task] = -1;
TaskDevicePort[task] = 0;
TaskDevicePin1PullUp[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGVAR_MAX; ++cv) {
TaskDevicePluginConfig[task][cv] = 0;
}
TaskDevicePin1Inversed[task] = false;
for (byte cv = 0; cv < PLUGIN_CONFIGFLOATVAR_MAX; ++cv) {
TaskDevicePluginConfigFloat[task][cv] = 0.0;
}
for (byte cv = 0; cv < PLUGIN_CONFIGLONGVAR_MAX; ++cv) {
TaskDevicePluginConfigLong[task][cv] = 0;
}
OLD_TaskDeviceSendData[task] = false;
TaskDeviceGlobalSync[task] = false;
TaskDeviceDataFeed[task] = 0;
TaskDeviceTimer[task] = 0;
TaskDeviceEnabled[task] = false;
}
unsigned long PID;
int Version;
@@ -683,12 +755,12 @@ struct SettingsStruct
long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX];
boolean OLD_TaskDeviceSendData[TASKS_MAX];
boolean TaskDeviceGlobalSync[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX];
byte TaskDeviceDataFeed[TASKS_MAX]; // When set to 0, only read local connected sensorsfeeds
unsigned long TaskDeviceTimer[TASKS_MAX];
boolean TaskDeviceEnabled[TASKS_MAX];
boolean ControllerEnabled[CONTROLLER_MAX];
boolean NotificationEnabled[NOTIFICATION_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX];
unsigned int TaskDeviceID[CONTROLLER_MAX][TASKS_MAX]; // IDX number (mainly used by Domoticz)
boolean TaskDeviceSendData[CONTROLLER_MAX][TASKS_MAX];
boolean Pin_status_led_Inversed;
boolean deepSleepOnFail;
@@ -860,15 +932,26 @@ struct NotificationSettingsStruct
//its safe to extend this struct, up to 4096 bytes, default values in config are 0
};
// 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() : TaskIndex(0) {
TaskDeviceName[0] = 0;
ExtraTaskSettingsStruct() : TaskIndex(TASKS_MAX) {
clear();
}
void clear() {
TaskIndex = TASKS_MAX;
for (byte j = 0; j < (NAME_FORMULA_LENGTH_MAX + 1); ++j) {
TaskDeviceName[j] = 0;
}
for (byte i = 0; i < VARS_PER_TASK; ++i) {
for (byte j = 0; j < 41; ++j) {
for (byte j = 0; j < (NAME_FORMULA_LENGTH_MAX + 1); ++j) {
TaskDeviceFormula[i][j] = 0;
TaskDeviceValueNames[i][j] = 0;
TaskDeviceValueDecimals[i] = 0;
TaskDeviceValueDecimals[i] = 2;
}
}
for (byte i = 0; i < PLUGIN_EXTRACONFIGVAR_MAX; ++i) {
@@ -877,10 +960,46 @@ struct ExtraTaskSettingsStruct
}
}
byte TaskIndex;
char TaskDeviceName[41];
char TaskDeviceFormula[VARS_PER_TASK][41];
char TaskDeviceValueNames[VARS_PER_TASK][41];
bool checkUniqueValueNames() {
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;
}
bool checkInvalidCharInNames(const char* name) {
int pos = 0;
while (*(name+pos) != 0) {
switch (*(name+pos)) {
case ',':
case ' ':
case '#':
case '[':
case ']':
return false;
}
++pos;
}
return true;
}
bool checkInvalidCharInNames() {
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;
}
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];
@@ -1053,20 +1172,26 @@ struct DeviceStruct
PullUpOption(false), InverseLogicOption(false), FormulaOption(false),
ValueCount(0), Custom(false), SendDataOption(false), GlobalSyncOption(false),
TimerOption(false), TimerOptional(false), DecimalsOnly(false) {}
byte Number;
byte Type;
byte VType;
byte Ports;
boolean PullUpOption;
boolean InverseLogicOption;
boolean FormulaOption;
byte ValueCount;
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)
boolean PullUpOption; // Allow to set internal pull-up resistors.
boolean InverseLogicOption; // Allow to invert the boolean state (e.g. a switch)
boolean FormulaOption; // Allow to enter a formula to convert values during read. (not possible with Custom enabled)
byte ValueCount; // The number of output values of a plugin. The value should match the number of keys PLUGIN_VALUENAME1_xxx
boolean Custom;
boolean SendDataOption;
boolean GlobalSyncOption;
boolean TimerOption;
boolean TimerOptional;
boolean DecimalsOnly;
boolean SendDataOption; // Allow to send data to a controller.
boolean GlobalSyncOption; // No longer used. Was used for ESPeasy values sync between nodes
boolean TimerOption; // Allow to set the "Interval" timer for the plugin.
boolean TimerOptional; // When taskdevice timer is not set and not optional, use default "Interval" delay (Settings.Delay)
boolean DecimalsOnly; // Allow to set the number of decimals (otherwise treated a 0 decimals)
} Device[DEVICES_MAX + 1]; // 1 more because first device is empty device
struct ProtocolStruct
-2
View File
@@ -195,8 +195,6 @@ void setup()
// setWifiMode(WIFI_STA);
checkRuleSets();
ExtraTaskSettings.TaskIndex = 255; // make sure this is an unused nr to prevent cache load on boot
// if different version, eeprom settings structure has changed. Full Reset needed
// on a fresh ESP module eeprom values are set to 255. Version results into -1 (signed int)
if (Settings.Version != VERSION || Settings.PID != ESP_PROJECT_PID)
+697
View File
@@ -0,0 +1,697 @@
/********************************************************************************************\
SPIFFS error handling
Look here for error # reference: https://github.com/pellepl/spiffs/blob/master/src/spiffs.h
\*********************************************************************************************/
#define SPIFFS_CHECK(result, fname) if (!(result)) { return(FileError(__LINE__, fname)); }
String FileError(int line, const char * fname)
{
String err = F("FS : Error while reading/writing ");
err += fname;
err += F(" in ");
err += line;
addLog(LOG_LEVEL_ERROR, err);
return(err);
}
/********************************************************************************************\
Keep track of number of flash writes.
\*********************************************************************************************/
void flashCount()
{
if (RTC.flashDayCounter <= MAX_FLASHWRITES_PER_DAY)
RTC.flashDayCounter++;
RTC.flashCounter++;
saveToRTC();
}
String flashGuard()
{
checkRAM(F("flashGuard"));
if (RTC.flashDayCounter > MAX_FLASHWRITES_PER_DAY)
{
String log = F("FS : Daily flash write rate exceeded! (powercycle to reset this)");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
flashCount();
return(String());
}
//use this in function that can return an error string. it automaticly returns with an error string if there where too many flash writes.
#define FLASH_GUARD() { String flashErr=flashGuard(); if (flashErr.length()) return(flashErr); }
/********************************************************************************************\
Fix stuff to clear out differences between releases
\*********************************************************************************************/
String BuildFixes()
{
checkRAM(F("BuildFixes"));
Serial.println(F("\nBuild changed!"));
if (Settings.Build < 145)
{
String fname=F(FILE_NOTIFICATION);
fs::File f = SPIFFS.open(fname, "w");
SPIFFS_CHECK(f, fname.c_str());
if (f)
{
for (int x = 0; x < 4096; x++)
{
SPIFFS_CHECK(f.write(0), fname.c_str());
}
f.close();
}
}
if (Settings.Build < 20101)
{
Serial.println(F("Fix reset Pin"));
Settings.Pin_Reset = -1;
}
if (Settings.Build < 20102) {
// Settings were 'mangled' by using older version
// Have to patch settings to make sure no bogus data is being used.
Serial.println(F("Fix settings with uninitalized data or corrupted by switching between versions"));
Settings.UseRTOSMultitasking = false;
Settings.Pin_Reset = -1;
Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY;
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNANE_AS_CLIENTID;
Settings.StructSize = sizeof(Settings);
}
Settings.Build = BUILD;
return(SaveSettings());
}
/********************************************************************************************\
Mount FS and check config.dat
\*********************************************************************************************/
void fileSystemCheck()
{
checkRAM(F("fileSystemCheck"));
addLog(LOG_LEVEL_INFO, F("FS : Mounting..."));
if (SPIFFS.begin())
{
#if defined(ESP8266)
fs::FSInfo fs_info;
SPIFFS.info(fs_info);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("FS : Mount successful, used ");
log=log+fs_info.usedBytes;
log=log+F(" bytes of ");
log=log+fs_info.totalBytes;
addLog(LOG_LEVEL_INFO, log);
}
#endif
fs::File f = SPIFFS.open(FILE_CONFIG, "r");
if (!f)
{
ResetFactory();
}
f.close();
}
else
{
String log = F("FS : Mount failed");
Serial.println(log);
addLog(LOG_LEVEL_ERROR, log);
ResetFactory();
}
}
/********************************************************************************************\
Save settings to SPIFFS
\*********************************************************************************************/
String SaveSettings(void)
{
checkRAM(F("SaveSettings"));
MD5Builder md5;
uint8_t tmp_md5[16] = {0};
String err;
Settings.StructSize = sizeof(struct SettingsStruct);
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
/*
memcpy( Settings.ProgmemMd5, CRCValues.runTimeMD5, 16);
md5.begin();
md5.add((uint8_t *)&Settings, sizeof(Settings)-16);
md5.calculate();
md5.getBytes(tmp_md5);
if (memcmp(tmp_md5, Settings.md5, 16) != 0) {
// Settings have changed, save to file.
memcpy(Settings.md5, tmp_md5, 16);
*/
err=SaveToFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof(Settings));
if (err.length())
return(err);
// }
memcpy( SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16);
md5.begin();
md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings)-16);
md5.calculate();
md5.getBytes(tmp_md5);
if (memcmp(tmp_md5, SecuritySettings.md5, 16) != 0) {
// Settings have changed, save to file.
memcpy(SecuritySettings.md5, tmp_md5, 16);
err=SaveToFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof(SecuritySettings));
if (WifiIsAP(WiFi.getMode())) {
// Security settings are saved, may be update of WiFi settings or hostname.
wifiSetupConnect = true;
}
}
return (err);
}
/********************************************************************************************\
Load settings from SPIFFS
\*********************************************************************************************/
String LoadSettings()
{
checkRAM(F("LoadSettings"));
String err;
uint8_t calculatedMd5[16];
MD5Builder md5;
err=LoadFromFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof( SettingsStruct));
if (err.length())
return(err);
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
/*
if (Settings.StructSize > 16) {
md5.begin();
md5.add((uint8_t *)&Settings, Settings.StructSize -16);
md5.calculate();
md5.getBytes(calculatedMd5);
}
if (memcmp (calculatedMd5, Settings.md5,16)==0){
addLog(LOG_LEVEL_INFO, F("CRC : Settings CRC ...OK"));
if (memcmp(Settings.ProgmemMd5, CRCValues.runTimeMD5, 16)!=0)
addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings"));
}
else{
addLog(LOG_LEVEL_ERROR, F("CRC : Settings CRC ...FAIL"));
}
*/
err=LoadFromFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof( SecurityStruct));
md5.begin();
md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings)-16);
md5.calculate();
md5.getBytes(calculatedMd5);
if (memcmp (calculatedMd5, SecuritySettings.md5, 16)==0){
addLog(LOG_LEVEL_INFO, F("CRC : SecuritySettings CRC ...OK "));
if (memcmp(SecuritySettings.ProgmemMd5,CRCValues.runTimeMD5, 16)!=0)
addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings"));
}
else{
addLog(LOG_LEVEL_ERROR, F("CRC : SecuritySettings CRC ...FAIL"));
}
setUseStaticIP(useStaticIP());
ExtraTaskSettings.clear(); // make sure these will not contain old settings.
return(err);
}
/********************************************************************************************\
Offsets in settings files
\*********************************************************************************************/
bool getSettingsParameters(SettingsType settingsType, int index, int& max_index, int& offset, int& max_size, int& struct_size) {
struct_size = 0;
switch (settingsType) {
case TaskSettings_Type:
max_index = TASKS_MAX;
offset = DAT_OFFSET_TASKS + (index * DAT_TASKS_DISTANCE);
max_size = DAT_TASKS_SIZE;
struct_size = sizeof(ExtraTaskSettingsStruct);
break;
case CustomTaskSettings_Type:
max_index = TASKS_MAX;
offset = DAT_OFFSET_TASKS + (index * DAT_TASKS_DISTANCE) + DAT_TASKS_CUSTOM_OFFSET;
max_size = DAT_TASKS_CUSTOM_SIZE;
// struct_size may differ.
break;
case ControllerSettings_Type:
max_index = CONTROLLER_MAX;
offset = DAT_OFFSET_CONTROLLER + (index * DAT_CONTROLLER_SIZE);
max_size = DAT_CONTROLLER_SIZE;
struct_size = sizeof(ControllerSettingsStruct);
break;
case CustomControllerSettings_Type:
max_index = CONTROLLER_MAX;
offset = DAT_OFFSET_CUSTOM_CONTROLLER + (index * DAT_CUSTOM_CONTROLLER_SIZE);
max_size = DAT_CUSTOM_CONTROLLER_SIZE;
// struct_size may differ.
break;
case NotificationSettings_Type:
max_index = NOTIFICATION_MAX;
offset = index * DAT_NOTIFICATION_SIZE;
max_size = DAT_NOTIFICATION_SIZE;
struct_size = sizeof(NotificationSettingsStruct);
break;
default:
max_index = -1;
offset = -1;
return false;
}
return true;
}
bool getAndLogSettingsParameters(bool read, SettingsType settingsType, int index, int& offset, int& max_size) {
if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) {
String log = read ? F("Read") : F("Write");
log += F(" settings: ");
log += getSettingsTypeString(settingsType);
log += F(" index: ");
log += index;
addLog(LOG_LEVEL_DEBUG_DEV, log);
}
return getSettingsParameters(settingsType, index, offset, max_size);
}
bool getSettingsParameters(SettingsType settingsType, int index, int& offset, int& max_size) {
int max_index = -1;
int struct_size;
if (!getSettingsParameters(settingsType, index, max_index, offset, max_size, struct_size))
return false;
if (index >= 0 && index < max_index) return true;
offset = -1;
return false;
}
/********************************************************************************************\
Save Task settings to SPIFFS
\*********************************************************************************************/
String SaveTaskSettings(byte TaskIndex)
{
checkRAM(F("SaveTaskSettings"));
if (ExtraTaskSettings.TaskIndex != TaskIndex)
return F("SaveTaskSettings taskIndex does not match");
String err = SaveToFile(TaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
if (err.length() == 0)
err = checkTaskSettings(TaskIndex);
return err;
}
/********************************************************************************************\
Load Task settings from SPIFFS
\*********************************************************************************************/
String LoadTaskSettings(byte TaskIndex)
{
checkRAM(F("LoadTaskSettings"));
if (ExtraTaskSettings.TaskIndex == TaskIndex)
return(String()); //already loaded
ExtraTaskSettings.clear();
String result = "";
result = LoadFromFile(TaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
// After loading, some settings may need patching.
ExtraTaskSettings.TaskIndex = TaskIndex; // Needed when an empty task was requested
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) {
// if field set empty, reload defaults
struct EventStruct TempEvent;
TempEvent.TaskIndex = TaskIndex;
String dummyString;
//the plugin call should populate ExtraTaskSettings with its default values.
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, &TempEvent, dummyString);
}
return result;
}
/********************************************************************************************\
Save Custom Task settings to SPIFFS
\*********************************************************************************************/
String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveCustomTaskSettings"));
return(SaveToFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Clear custom task settings
\*********************************************************************************************/
String ClearCustomTaskSettings(int TaskIndex)
{
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom task settings"));
return(ClearInFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG));
}
/********************************************************************************************\
Load Custom Task settings to SPIFFS
\*********************************************************************************************/
String LoadCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadCustomTaskSettings"));
return(LoadFromFile(CustomTaskSettings_Type, TaskIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Save Controller settings to SPIFFS
\*********************************************************************************************/
String SaveControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveControllerSettings"));
return SaveToFile(ControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize);
}
/********************************************************************************************\
Load Controller settings to SPIFFS
\*********************************************************************************************/
String LoadControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadControllerSettings"));
return(LoadFromFile(ControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Clear Custom Controller settings
\*********************************************************************************************/
String ClearCustomControllerSettings(int ControllerIndex)
{
checkRAM(F("ClearCustomControllerSettings"));
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom controller settings"));
return(ClearInFile(CustomControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG));
}
/********************************************************************************************\
Save Custom Controller settings to SPIFFS
\*********************************************************************************************/
String SaveCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
{
checkRAM(F("SaveCustomControllerSettings"));
return SaveToFile(CustomControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize);
}
/********************************************************************************************\
Load Custom Controller settings to SPIFFS
\*********************************************************************************************/
String LoadCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
{
checkRAM(F("LoadCustomControllerSettings"));
return(LoadFromFile(CustomControllerSettings_Type, ControllerIndex, (char*)FILE_CONFIG, memAddress, datasize));
}
/********************************************************************************************\
Save Controller settings to SPIFFS
\*********************************************************************************************/
String SaveNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveNotificationSettings"));
return SaveToFile(NotificationSettings_Type, NotificationIndex, (char*)FILE_NOTIFICATION, memAddress, datasize);
}
/********************************************************************************************\
Load Controller settings to SPIFFS
\*********************************************************************************************/
String LoadNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadNotificationSettings"));
return(LoadFromFile(NotificationSettings_Type, NotificationIndex, (char*)FILE_NOTIFICATION, memAddress, datasize));
}
/********************************************************************************************\
Init a file with zeros on SPIFFS
\*********************************************************************************************/
String InitFile(const char* fname, int datasize)
{
checkRAM(F("InitFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "w");
SPIFFS_CHECK(f, fname);
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(0), fname);
}
f.close();
//OK
return String();
}
/********************************************************************************************\
Save data into config file on SPIFFS
\*********************************************************************************************/
String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
{
if (index < 0) {
String log = F("SaveToFile: ");
log += fname;
log += F(" ERROR, invalid position in file");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
checkRAM(F("SaveToFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
byte *pointerToByteToSave = memAddress;
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(*pointerToByteToSave), fname);
pointerToByteToSave++;
}
f.close();
String log = F("FILE : Saved ");
log=log+fname;
addLog(LOG_LEVEL_INFO, log);
//OK
return String();
}
/********************************************************************************************\
Clear a certain area in a file (set to 0)
\*********************************************************************************************/
String ClearInFile(char* fname, int index, int datasize)
{
if (index < 0) {
String log = F("ClearInFile: ");
log += fname;
log += F(" ERROR, invalid position in file");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
checkRAM(F("ClearInFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(0), fname);
}
f.close();
//OK
return String();
}
/********************************************************************************************\
Load data from config file on SPIFFS
\*********************************************************************************************/
String LoadFromFile(char* fname, int offset, byte* memAddress, int datasize)
{
if (offset < 0) {
String log = F("LoadFromFile: ");
log += fname;
log += F(" ERROR, invalid position in file");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
START_TIMER;
checkRAM(F("LoadFromFile"));
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(offset, fs::SeekSet), fname);
SPIFFS_CHECK(f.read(memAddress,datasize), fname);
f.close();
STOP_TIMER(LOADFILE_STATS);
return(String());
}
/********************************************************************************************\
Wrapper functions to handle errors in accessing settings
\*********************************************************************************************/
String getSettingsFileIndexRangeError(bool read, SettingsType settingsType, int index) {
if (settingsType >= SettingsType_MAX) {
String error = F("Unknown settingsType: ");
error += static_cast<int>(settingsType);
return error;
}
String error = read ? F("Load") : F("Save");
error += getSettingsTypeString(settingsType);
error += F(" index out of range: ");
error += index;
return error;
}
String getSettingsFileDatasizeError(bool read, SettingsType settingsType, int index, int datasize, int max_size) {
String error = read ? F("Load") : F("Save");
error += getSettingsTypeString(settingsType);
error += '(';
error += index;
error += F(") datasize(");
error += datasize;
error += F(") > max_size(");
error += max_size;
error += ')';
return error;
}
String LoadFromFile(SettingsType settingsType, int index, char* fname, byte* memAddress, int datasize) {
bool read = true;
int offset, max_size;
if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) {
return getSettingsFileIndexRangeError(read, settingsType, index);
}
if (datasize > max_size)
return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size);
return(LoadFromFile(fname, offset, memAddress, datasize));
}
String SaveToFile(SettingsType settingsType, int index, char* fname, byte* memAddress, int datasize) {
bool read = false;
int offset, max_size;
if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) {
return getSettingsFileIndexRangeError(read, settingsType, index);
}
if (datasize > max_size)
return getSettingsFileDatasizeError(read, settingsType, index, datasize, max_size);
return(SaveToFile(fname, offset, memAddress, datasize));
}
String ClearInFile(SettingsType settingsType, int index, char* fname) {
bool read = false;
int offset, max_size;
if (!getAndLogSettingsParameters(read, settingsType, index, offset, max_size)) {
return getSettingsFileIndexRangeError(read, settingsType, index);
}
return(ClearInFile(fname, offset, max_size));
}
/********************************************************************************************\
Check SPIFFS area settings
\*********************************************************************************************/
int SpiffsSectors()
{
checkRAM(F("SpiffsSectors"));
#if defined(ESP8266)
uint32_t _sectorStart = ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE;
uint32_t _sectorEnd = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
return _sectorEnd - _sectorStart;
#endif
#if defined(ESP32)
return 32;
#endif
}
/********************************************************************************************\
Get partition table information
\*********************************************************************************************/
#ifdef ESP32
String getPartitionType(byte pType, byte pSubType) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
esp_partition_subtype_t partitionSubType = static_cast<esp_partition_subtype_t>(pSubType);
if (partitionType == ESP_PARTITION_TYPE_APP) {
if (partitionSubType >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN &&
partitionSubType < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
String result = F("OTA partition ");
result += (partitionSubType - ESP_PARTITION_SUBTYPE_APP_OTA_MIN);
return result;
}
switch (partitionSubType) {
case ESP_PARTITION_SUBTYPE_APP_FACTORY: return F("Factory app");
case ESP_PARTITION_SUBTYPE_APP_TEST: return F("Test app");
default: break;
}
}
if (partitionType == ESP_PARTITION_TYPE_DATA) {
switch (partitionSubType) {
case ESP_PARTITION_SUBTYPE_DATA_OTA: return F("OTA selection");
case ESP_PARTITION_SUBTYPE_DATA_PHY: return F("PHY init data");
case ESP_PARTITION_SUBTYPE_DATA_NVS: return F("NVS");
case ESP_PARTITION_SUBTYPE_DATA_COREDUMP: return F("COREDUMP");
case ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD: return F("ESPHTTPD");
case ESP_PARTITION_SUBTYPE_DATA_FAT: return F("FAT");
case ESP_PARTITION_SUBTYPE_DATA_SPIFFS: return F("SPIFFS");
default: break;
}
}
String result = F("Unknown(");
result += partitionSubType;
result += ')';
return result;
}
String getPartitionTableHeader(const String& itemSep, const String& lineEnd) {
String result;
result += F("Address");
result += itemSep;
result += F("Size");
result += itemSep;
result += F("Label");
result += itemSep;
result += F("Partition Type");
result += itemSep;
result += F("Encrypted");
result += lineEnd;
return result;
}
String getPartitionTable(byte pType, const String& itemSep, const String& lineEnd) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
String result;
const esp_partition_t * _mypart;
esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, ESP_PARTITION_SUBTYPE_ANY, NULL);
if (_mypartiterator) {
do {
_mypart = esp_partition_get(_mypartiterator);
result += formatToHex(_mypart->address);
result += itemSep;
result += formatToHex_decimal(_mypart->size, 1024);
result += itemSep;
result += _mypart->label;
result += itemSep;
result += getPartitionType(_mypart->type, _mypart->subtype);
result += itemSep;
result += (_mypart->encrypted ? F("Yes") : F("-"));
result += lineEnd;
} while ((_mypartiterator = esp_partition_next(_mypartiterator)) != NULL);
}
esp_partition_iterator_release(_mypartiterator);
return result;
}
#endif
+43 -622
View File
@@ -133,8 +133,8 @@ int8_t getTaskIndexByName(String TaskNameSearch)
for (byte x = 0; x < TASKS_MAX; x++)
{
LoadTaskSettings(x);
String TaskName = ExtraTaskSettings.TaskDeviceName;
if ((ExtraTaskSettings.TaskDeviceName[0] != 0 ) && (TaskNameSearch.equalsIgnoreCase(TaskName)))
String TaskName = getTaskDeviceName(x);
if ((TaskName.length() != 0 ) && (TaskNameSearch.equalsIgnoreCase(TaskName)))
{
return x;
}
@@ -143,30 +143,6 @@ int8_t getTaskIndexByName(String TaskNameSearch)
}
void flashCount()
{
if (RTC.flashDayCounter <= MAX_FLASHWRITES_PER_DAY)
RTC.flashDayCounter++;
RTC.flashCounter++;
saveToRTC();
}
String flashGuard()
{
checkRAM(F("flashGuard"));
if (RTC.flashDayCounter > MAX_FLASHWRITES_PER_DAY)
{
String log = F("FS : Daily flash write rate exceeded! (powercycle to reset this)");
addLog(LOG_LEVEL_ERROR, log);
return log;
}
flashCount();
return(String());
}
//use this in function that can return an error string. it automaticly returns with an error string if there where too many flash writes.
#define FLASH_GUARD() { String flashErr=flashGuard(); if (flashErr.length()) return(flashErr); }
/*********************************************************************************************\
set pin mode & state (info table)
@@ -402,145 +378,49 @@ void parseCommandString(struct EventStruct *event, const String& string)
void taskClear(byte taskIndex, boolean save)
{
checkRAM(F("taskClear"));
Settings.TaskDeviceNumber[taskIndex] = 0;
ExtraTaskSettings.TaskDeviceName[0] = 0;
Settings.TaskDeviceDataFeed[taskIndex] = 0;
Settings.TaskDevicePin1[taskIndex] = -1;
Settings.TaskDevicePin2[taskIndex] = -1;
Settings.TaskDevicePin3[taskIndex] = -1;
Settings.TaskDevicePort[taskIndex] = 0;
Settings.TaskDeviceGlobalSync[taskIndex] = false;
Settings.TaskDeviceTimer[taskIndex] = 0;
Settings.TaskDeviceEnabled[taskIndex] = false;
for (byte controllerNr = 0; controllerNr < CONTROLLER_MAX; controllerNr++)
{
Settings.TaskDeviceID[controllerNr][taskIndex] = 0;
Settings.TaskDeviceSendData[controllerNr][taskIndex] = true;
}
for (byte x = 0; x < PLUGIN_CONFIGVAR_MAX; x++)
Settings.TaskDevicePluginConfig[taskIndex][x] = 0;
for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++)
{
ExtraTaskSettings.TaskDeviceFormula[varNr][0] = 0;
ExtraTaskSettings.TaskDeviceValueNames[varNr][0] = 0;
ExtraTaskSettings.TaskDeviceValueDecimals[varNr] = 2;
}
for (byte varNr = 0; varNr < PLUGIN_EXTRACONFIGVAR_MAX; varNr++)
{
ExtraTaskSettings.TaskDevicePluginConfigLong[varNr] = 0;
ExtraTaskSettings.TaskDevicePluginConfig[varNr] = 0;
}
if (save)
{
Settings.clearTask(taskIndex);
ExtraTaskSettings.clear(); // Invalidate any cached values.
ExtraTaskSettings.TaskIndex = taskIndex;
if (save) {
SaveTaskSettings(taskIndex);
SaveSettings();
}
}
/********************************************************************************************\
SPIFFS error handling
Look here for error # reference: https://github.com/pellepl/spiffs/blob/master/src/spiffs.h
\*********************************************************************************************/
#define SPIFFS_CHECK(result, fname) if (!(result)) { return(FileError(__LINE__, fname)); }
String FileError(int line, const char * fname)
{
String err = F("FS : Error while reading/writing ");
err += fname;
err += F(" in ");
err += line;
addLog(LOG_LEVEL_ERROR, err);
return(err);
}
/********************************************************************************************\
Fix stuff to clear out differences between releases
\*********************************************************************************************/
String BuildFixes()
{
checkRAM(F("BuildFixes"));
Serial.println(F("\nBuild changed!"));
if (Settings.Build < 145)
{
String fname=F(FILE_NOTIFICATION);
fs::File f = SPIFFS.open(fname, "w");
SPIFFS_CHECK(f, fname.c_str());
if (f)
{
for (int x = 0; x < 4096; x++)
{
SPIFFS_CHECK(f.write(0), fname.c_str());
String checkTaskSettings(byte taskIndex) {
String err = LoadTaskSettings(taskIndex);
if (err.length() > 0) return err;
if (!ExtraTaskSettings.checkUniqueValueNames()) {
return F("Use unique value names");
}
if (!ExtraTaskSettings.checkInvalidCharInNames()) {
return F("Invalid character in names. Do not use ',#[]' or space.");
}
String deviceName = ExtraTaskSettings.TaskDeviceName;
if (deviceName.length() == 0) {
if (Settings.TaskDeviceEnabled[taskIndex]) {
// Decide what to do here, for now give a warning when task is enabled.
return F("Warning: Task Device Name is empty. It is adviced to give tasks an unique name");
}
}
for (int i = 0; i < TASKS_MAX; ++i) {
if (i != taskIndex) {
LoadTaskSettings(i);
if (ExtraTaskSettings.TaskDeviceName[0] != 0) {
if (strcasecmp(ExtraTaskSettings.TaskDeviceName, deviceName.c_str()) == 0) {
err = F("Task Device Name is not unique, conflicts with task ID #");
err += (i+1);
return err;
}
}
f.close();
}
}
if (Settings.Build < 20101)
{
Serial.println(F("Fix reset Pin"));
Settings.Pin_Reset = -1;
}
if (Settings.Build < 20102) {
// Settings were 'mangled' by using older version
// Have to patch settings to make sure no bogus data is being used.
Serial.println(F("Fix settings with uninitalized data or corrupted by switching between versions"));
Settings.UseRTOSMultitasking = false;
Settings.Pin_Reset = -1;
Settings.SyslogFacility = DEFAULT_SYSLOG_FACILITY;
Settings.MQTTUseUnitNameAsClientId = DEFAULT_MQTT_USE_UNITNANE_AS_CLIENTID;
Settings.StructSize = sizeof(Settings);
}
Settings.Build = BUILD;
return(SaveSettings());
err = LoadTaskSettings(taskIndex);
return err;
}
/********************************************************************************************\
Mount FS and check config.dat
\*********************************************************************************************/
void fileSystemCheck()
{
checkRAM(F("fileSystemCheck"));
addLog(LOG_LEVEL_INFO, F("FS : Mounting..."));
if (SPIFFS.begin())
{
#if defined(ESP8266)
fs::FSInfo fs_info;
SPIFFS.info(fs_info);
if (loglevelActiveFor(LOG_LEVEL_INFO)) {
String log = F("FS : Mount successful, used ");
log=log+fs_info.usedBytes;
log=log+F(" bytes of ");
log=log+fs_info.totalBytes;
addLog(LOG_LEVEL_INFO, log);
}
#endif
fs::File f = SPIFFS.open(FILE_CONFIG, "r");
if (!f)
{
ResetFactory();
}
f.close();
}
else
{
String log = F("FS : Mount failed");
Serial.println(log);
addLog(LOG_LEVEL_ERROR, log);
ResetFactory();
}
}
/********************************************************************************************\
Find device index corresponding to task number setting
@@ -723,394 +603,12 @@ uint32_t progMemMD5check(){
return 0;
}
/********************************************************************************************\
Save settings to SPIFFS
Handler for keeping ExtraTaskSettings up to date using cache
\*********************************************************************************************/
String SaveSettings(void)
{
checkRAM(F("SaveSettings"));
MD5Builder md5;
uint8_t tmp_md5[16] = {0};
String err;
Settings.StructSize = sizeof(struct SettingsStruct);
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
/*
memcpy( Settings.ProgmemMd5, CRCValues.runTimeMD5, 16);
md5.begin();
md5.add((uint8_t *)&Settings, sizeof(Settings)-16);
md5.calculate();
md5.getBytes(tmp_md5);
if (memcmp(tmp_md5, Settings.md5, 16) != 0) {
// Settings have changed, save to file.
memcpy(Settings.md5, tmp_md5, 16);
*/
err=SaveToFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof(Settings));
if (err.length())
return(err);
// }
memcpy( SecuritySettings.ProgmemMd5, CRCValues.runTimeMD5, 16);
md5.begin();
md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings)-16);
md5.calculate();
md5.getBytes(tmp_md5);
if (memcmp(tmp_md5, SecuritySettings.md5, 16) != 0) {
// Settings have changed, save to file.
memcpy(SecuritySettings.md5, tmp_md5, 16);
err=SaveToFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof(SecuritySettings));
if (WifiIsAP(WiFi.getMode())) {
// Security settings are saved, may be update of WiFi settings or hostname.
wifiSetupConnect = true;
}
}
return (err);
}
/********************************************************************************************\
Load settings from SPIFFS
\*********************************************************************************************/
String LoadSettings()
{
checkRAM(F("LoadSettings"));
String err;
uint8_t calculatedMd5[16];
MD5Builder md5;
err=LoadFromFile((char*)FILE_CONFIG, 0, (byte*)&Settings, sizeof( SettingsStruct));
if (err.length())
return(err);
// FIXME @TD-er: As discussed in #1292, the CRC for the settings is now disabled.
/*
if (Settings.StructSize > 16) {
md5.begin();
md5.add((uint8_t *)&Settings, Settings.StructSize -16);
md5.calculate();
md5.getBytes(calculatedMd5);
}
if (memcmp (calculatedMd5, Settings.md5,16)==0){
addLog(LOG_LEVEL_INFO, F("CRC : Settings CRC ...OK"));
if (memcmp(Settings.ProgmemMd5, CRCValues.runTimeMD5, 16)!=0)
addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings"));
}
else{
addLog(LOG_LEVEL_ERROR, F("CRC : Settings CRC ...FAIL"));
}
*/
err=LoadFromFile((char*)FILE_SECURITY, 0, (byte*)&SecuritySettings, sizeof( SecurityStruct));
md5.begin();
md5.add((uint8_t *)&SecuritySettings, sizeof(SecuritySettings)-16);
md5.calculate();
md5.getBytes(calculatedMd5);
if (memcmp (calculatedMd5, SecuritySettings.md5, 16)==0){
addLog(LOG_LEVEL_INFO, F("CRC : SecuritySettings CRC ...OK "));
if (memcmp(SecuritySettings.ProgmemMd5,CRCValues.runTimeMD5, 16)!=0)
addLog(LOG_LEVEL_INFO, F("CRC : binary has changed since last save of Settings"));
}
else{
addLog(LOG_LEVEL_ERROR, F("CRC : SecuritySettings CRC ...FAIL"));
}
setUseStaticIP(useStaticIP());
return(err);
}
/********************************************************************************************\
Save Task settings to SPIFFS
\*********************************************************************************************/
String SaveTaskSettings(byte TaskIndex)
{
checkRAM(F("SaveTaskSettings"));
if (DAT_TASKS_SIZE < sizeof(struct ExtraTaskSettingsStruct))
return F("SaveTaskSettings too big");
if (TaskIndex >= TASKS_MAX)
return F("SaveTaskSettings TaskIndex too big");
ExtraTaskSettings.TaskIndex = TaskIndex;
return(SaveToFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct)));
}
/********************************************************************************************\
Load Task settings from SPIFFS
\*********************************************************************************************/
String LoadTaskSettings(byte TaskIndex)
{
checkRAM(F("LoadTaskSettings"));
//already loaded
if (ExtraTaskSettings.TaskIndex == TaskIndex)
return(String());
if (TaskIndex >= TASKS_MAX)
return F("LoadTaskSettings TaskIndex too big");
String result = "";
result = LoadFromFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE), (byte*)&ExtraTaskSettings, sizeof(struct ExtraTaskSettingsStruct));
ExtraTaskSettings.TaskIndex = TaskIndex; // Needed when an empty task was requested
return result;
}
/********************************************************************************************\
Save Custom Task settings to SPIFFS
\*********************************************************************************************/
String SaveCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveCustomTaskSettings"));
if (datasize > DAT_TASKS_SIZE)
return F("SaveCustomTaskSettings too big");
if (TaskIndex >= TASKS_MAX)
return F("SaveCustomTaskSettings TaskIndex too big");
return(SaveToFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize));
}
/********************************************************************************************\
Clear custom task settings
\*********************************************************************************************/
String ClearCustomTaskSettings(int TaskIndex)
{
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom task settings"));
if (TaskIndex >= TASKS_MAX)
return F("ClearCustomTaskSettings TaskIndex too big");
return(ClearInFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, DAT_TASKS_CUSTOM_SIZE));
}
/********************************************************************************************\
Load Custom Task settings to SPIFFS
\*********************************************************************************************/
String LoadCustomTaskSettings(int TaskIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadCustomTaskSettings"));
if (datasize > DAT_TASKS_SIZE)
return (String(F("LoadCustomTaskSettings too big")));
if (TaskIndex >= TASKS_MAX)
return F("LoadCustomTaskSettings TaskIndex too big");
return(LoadFromFile((char*)FILE_CONFIG, DAT_OFFSET_TASKS + (TaskIndex * DAT_TASKS_SIZE) + DAT_TASKS_CUSTOM_OFFSET, memAddress, datasize));
}
/********************************************************************************************\
Save Controller settings to SPIFFS
\*********************************************************************************************/
String SaveControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveControllerSettings"));
if (datasize > DAT_CONTROLLER_SIZE)
return F("SaveControllerSettings too big");
return SaveToFile((char*)FILE_CONFIG, DAT_OFFSET_CONTROLLER + (ControllerIndex * DAT_CONTROLLER_SIZE), memAddress, datasize);
}
/********************************************************************************************\
Load Controller settings to SPIFFS
\*********************************************************************************************/
String LoadControllerSettings(int ControllerIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadControllerSettings"));
if (datasize > DAT_CONTROLLER_SIZE)
return F("LoadControllerSettings too big");
return(LoadFromFile((char*)FILE_CONFIG, DAT_OFFSET_CONTROLLER + (ControllerIndex * DAT_CONTROLLER_SIZE), memAddress, datasize));
}
/********************************************************************************************\
Clear Custom Controller settings
\*********************************************************************************************/
String ClearCustomControllerSettings(int ControllerIndex)
{
checkRAM(F("ClearCustomControllerSettings"));
// addLog(LOG_LEVEL_DEBUG, F("Clearing custom controller settings"));
return(ClearInFile((char*)FILE_CONFIG, DAT_OFFSET_CUSTOM_CONTROLLER + (ControllerIndex * DAT_CUSTOM_CONTROLLER_SIZE), DAT_CUSTOM_CONTROLLER_SIZE));
}
/********************************************************************************************\
Save Custom Controller settings to SPIFFS
\*********************************************************************************************/
String SaveCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
{
checkRAM(F("SaveCustomControllerSettings"));
if (datasize > DAT_CUSTOM_CONTROLLER_SIZE)
return F("SaveCustomControllerSettings too big");
return SaveToFile((char*)FILE_CONFIG, DAT_OFFSET_CUSTOM_CONTROLLER + (ControllerIndex * DAT_CUSTOM_CONTROLLER_SIZE), memAddress, datasize);
}
/********************************************************************************************\
Load Custom Controller settings to SPIFFS
\*********************************************************************************************/
String LoadCustomControllerSettings(int ControllerIndex,byte* memAddress, int datasize)
{
checkRAM(F("LoadCustomControllerSettings"));
if (datasize > DAT_CUSTOM_CONTROLLER_SIZE)
return(F("LoadCustomControllerSettings too big"));
return(LoadFromFile((char*)FILE_CONFIG, DAT_OFFSET_CUSTOM_CONTROLLER + (ControllerIndex * DAT_CUSTOM_CONTROLLER_SIZE), memAddress, datasize));
}
/********************************************************************************************\
Save Controller settings to SPIFFS
\*********************************************************************************************/
String SaveNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
{
checkRAM(F("SaveNotificationSettings"));
if (datasize > DAT_NOTIFICATION_SIZE)
return F("SaveNotificationSettings too big");
return SaveToFile((char*)FILE_NOTIFICATION, NotificationIndex * DAT_NOTIFICATION_SIZE, memAddress, datasize);
}
/********************************************************************************************\
Load Controller settings to SPIFFS
\*********************************************************************************************/
String LoadNotificationSettings(int NotificationIndex, byte* memAddress, int datasize)
{
checkRAM(F("LoadNotificationSettings"));
if (datasize > DAT_NOTIFICATION_SIZE)
return(F("LoadNotificationSettings too big"));
return(LoadFromFile((char*)FILE_NOTIFICATION, NotificationIndex * DAT_NOTIFICATION_SIZE, memAddress, datasize));
}
/********************************************************************************************\
Init a file with zeros on SPIFFS
\*********************************************************************************************/
String InitFile(const char* fname, int datasize)
{
checkRAM(F("InitFile"));
FLASH_GUARD();
fs::File f = SPIFFS.open(fname, "w");
SPIFFS_CHECK(f, fname);
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(0), fname);
}
f.close();
//OK
return String();
}
/********************************************************************************************\
Save data into config file on SPIFFS
\*********************************************************************************************/
String SaveToFile(char* fname, int index, byte* memAddress, int datasize)
{
checkRAM(F("SaveToFile"));
FLASH_GUARD();
String log = F("SaveToFile: ");
log += fname;
log += F(" index: ");
log += index;
log += F(" datasize: ");
log += datasize;
addLog(LOG_LEVEL_DEBUG, log);
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
byte *pointerToByteToSave = memAddress;
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(*pointerToByteToSave), fname);
pointerToByteToSave++;
}
f.close();
log = F("FILE : Saved ");
log=log+fname;
addLog(LOG_LEVEL_INFO, log);
//OK
return String();
}
/********************************************************************************************\
Clear a certain area in a file (set to 0)
\*********************************************************************************************/
String ClearInFile(char* fname, int index, int datasize)
{
checkRAM(F("ClearInFile"));
FLASH_GUARD();
String log = F("ClearInFile: ");
log += fname;
log += F(" index: ");
log += index;
log += F(" datasize: ");
log += datasize;
addLog(LOG_LEVEL_DEBUG, log);
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
for (int x = 0; x < datasize ; x++)
{
SPIFFS_CHECK(f.write(0), fname);
}
f.close();
//OK
return String();
}
/********************************************************************************************\
Load data from config file on SPIFFS
\*********************************************************************************************/
String LoadFromFile(char* fname, int index, byte* memAddress, int datasize)
{
START_TIMER;
checkRAM(F("LoadFromFile"));
if (loglevelActiveFor(LOG_LEVEL_DEBUG_DEV)) {
String log = F("LoadFromFile: ");
log += fname;
log += F(" index: ");
log += index;
log += F(" datasize: ");
log += datasize;
addLog(LOG_LEVEL_DEBUG_DEV, log);
}
fs::File f = SPIFFS.open(fname, "r+");
SPIFFS_CHECK(f, fname);
SPIFFS_CHECK(f.seek(index, fs::SeekSet), fname);
SPIFFS_CHECK(f.read(memAddress,datasize), fname);
f.close();
STOP_TIMER(LOADFILE_STATS);
return(String());
}
/********************************************************************************************\
Check SPIFFS area settings
\*********************************************************************************************/
int SpiffsSectors()
{
checkRAM(F("SpiffsSectors"));
#if defined(ESP8266)
uint32_t _sectorStart = ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE;
uint32_t _sectorEnd = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE;
return _sectorEnd - _sectorStart;
#endif
#if defined(ESP32)
return 32;
#endif
String getTaskDeviceName(byte TaskIndex) {
LoadTaskSettings(TaskIndex);
return ExtraTaskSettings.TaskDeviceName;
}
@@ -1171,7 +669,7 @@ void ResetFactory(void)
fname=FILE_RULES;
InitFile(fname.c_str(), 0);
LoadSettings();
Settings.clearAll();
// now we set all parameters that need to be non-zero as default value
#if DEFAULT_USE_STATIC_IP
@@ -1445,84 +943,6 @@ String getLWIPversion() {
#endif
/********************************************************************************************\
Get partition table information
\*********************************************************************************************/
#ifdef ESP32
String getPartitionType(byte pType, byte pSubType) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
esp_partition_subtype_t partitionSubType = static_cast<esp_partition_subtype_t>(pSubType);
if (partitionType == ESP_PARTITION_TYPE_APP) {
if (partitionSubType >= ESP_PARTITION_SUBTYPE_APP_OTA_MIN &&
partitionSubType < ESP_PARTITION_SUBTYPE_APP_OTA_MAX) {
String result = F("OTA partition ");
result += (partitionSubType - ESP_PARTITION_SUBTYPE_APP_OTA_MIN);
return result;
}
switch (partitionSubType) {
case ESP_PARTITION_SUBTYPE_APP_FACTORY: return F("Factory app");
case ESP_PARTITION_SUBTYPE_APP_TEST: return F("Test app");
default: break;
}
}
if (partitionType == ESP_PARTITION_TYPE_DATA) {
switch (partitionSubType) {
case ESP_PARTITION_SUBTYPE_DATA_OTA: return F("OTA selection");
case ESP_PARTITION_SUBTYPE_DATA_PHY: return F("PHY init data");
case ESP_PARTITION_SUBTYPE_DATA_NVS: return F("NVS");
case ESP_PARTITION_SUBTYPE_DATA_COREDUMP: return F("COREDUMP");
case ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD: return F("ESPHTTPD");
case ESP_PARTITION_SUBTYPE_DATA_FAT: return F("FAT");
case ESP_PARTITION_SUBTYPE_DATA_SPIFFS: return F("SPIFFS");
default: break;
}
}
String result = F("Unknown(");
result += partitionSubType;
result += ')';
return result;
}
String getPartitionTableHeader(const String& itemSep, const String& lineEnd) {
String result;
result += F("Address");
result += itemSep;
result += F("Size");
result += itemSep;
result += F("Label");
result += itemSep;
result += F("Partition Type");
result += itemSep;
result += F("Encrypted");
result += lineEnd;
return result;
}
String getPartitionTable(byte pType, const String& itemSep, const String& lineEnd) {
esp_partition_type_t partitionType = static_cast<esp_partition_type_t>(pType);
String result;
const esp_partition_t * _mypart;
esp_partition_iterator_t _mypartiterator = esp_partition_find(partitionType, ESP_PARTITION_SUBTYPE_ANY, NULL);
if (_mypartiterator) {
do {
_mypart = esp_partition_get(_mypartiterator);
result += formatToHex(_mypart->address);
result += itemSep;
result += formatToHex_decimal(_mypart->size, 1024);
result += itemSep;
result += _mypart->label;
result += itemSep;
result += getPartitionType(_mypart->type, _mypart->subtype);
result += itemSep;
result += (_mypart->encrypted ? F("Yes") : F("-"));
result += lineEnd;
} while ((_mypartiterator = esp_partition_next(_mypartiterator)) != NULL);
}
esp_partition_iterator_release(_mypartiterator);
return result;
}
#endif
/********************************************************************************************\
@@ -1946,9 +1366,10 @@ String parseTemplate(String &tmpString, byte lineSize)
if (Settings.TaskDeviceEnabled[y])
{
LoadTaskSettings(y);
if (ExtraTaskSettings.TaskDeviceName[0] != 0)
String taskDeviceName = getTaskDeviceName(y);
if (taskDeviceName.length() != 0)
{
if (deviceName.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName))
if (deviceName.equalsIgnoreCase(taskDeviceName))
{
boolean match = false;
for (byte z = 0; z < VARS_PER_TASK; z++)
@@ -3089,7 +2510,7 @@ void createRuleEvents(byte TaskIndex)
byte sensorType = Device[DeviceIndex].VType;
for (byte varNr = 0; varNr < Device[DeviceIndex].ValueCount; varNr++)
{
String eventString = ExtraTaskSettings.TaskDeviceName;
String eventString = getTaskDeviceName(TaskIndex);
eventString += F("#");
eventString += ExtraTaskSettings.TaskDeviceValueNames[varNr];
eventString += F("=");
@@ -3123,7 +2544,7 @@ void SendValueLogger(byte TaskIndex)
logger += F(",");
logger += Settings.Unit;
logger += F(",");
logger += ExtraTaskSettings.TaskDeviceName;
logger += getTaskDeviceName(TaskIndex);
logger += F(",");
logger += ExtraTaskSettings.TaskDeviceValueNames[varNr];
logger += F(",");
+3
View File
@@ -477,6 +477,8 @@ void parseSystemVariables(String& s, boolean useURLencode)
repl(F("%CR%"), F("\r"), s, useURLencode);
repl(F("%LF%"), F("\n"), s, useURLencode);
repl(F("%SP%"), F(" "), s, useURLencode); //space
repl(F("%R%"), F("\\r"), s, useURLencode);
repl(F("%N%"), F("\\n"), s, useURLencode);
SMART_REPL(F("%ip4%"),WiFi.localIP().toString().substring(WiFi.localIP().toString().lastIndexOf('.')+1)) //4th IP octet
SMART_REPL(F("%ip%"),WiFi.localIP().toString())
SMART_REPL(F("%rssi%"), String((wifiStatus == ESPEASY_WIFI_DISCONNECTED) ? 0 : WiFi.RSSI()))
@@ -520,6 +522,7 @@ void parseSystemVariables(String& s, boolean useURLencode)
SMART_REPL_T(F("%sunset"), replSunSetTimeString)
SMART_REPL_T(F("%sunrise"), replSunRiseTimeString)
// FIXME TD-er: Must make sure LoadTaskSettings has been performed before this is called.
repl(F("%tskname%"), ExtraTaskSettings.TaskDeviceName, s, useURLencode);
if (s.indexOf(F("%vname")) != -1) {
repl(F("%vname1%"), ExtraTaskSettings.TaskDeviceValueNames[0], s, useURLencode);
+27 -13
View File
@@ -427,7 +427,13 @@ bool isFormItem(const String& id)
void addHtmlError(String error){
if (error.length()>0)
{
TXBuffer += F("<div class=\"alert\"><span class=\"closebtn\" onclick=\"this.parentElement.style.display='none';\">&times;</span>");
TXBuffer += F("<div class=\"");
if (error.startsWith(F("Warn"))) {
TXBuffer += F("warning");
} else {
TXBuffer += F("alert");
}
TXBuffer += F("\"><span class=\"closebtn\" onclick=\"this.parentElement.style.display='none';\">&times;</span>");
TXBuffer += error;
TXBuffer += F("</div>");
}
@@ -1821,12 +1827,15 @@ void handle_devices() {
}
const int edit = getFormItemInt(F("edit"), 0);
// taskIndex in the URL is 1 ... TASKS_MAX
// For use in other functions, set it to 0 ... (TASKS_MAX - 1)
byte taskIndex = getFormItemInt(F("index"), 0);
boolean taskIndexNotSet = taskIndex == 0;
--taskIndex;
byte DeviceIndex = 0;
LoadTaskSettings(taskIndex); // Make sure ExtraTaskSettings are up-to-date
// FIXME TD-er: Might have to clear any caches here.
if (edit != 0 && !taskIndexNotSet) // when form submitted
{
if (Settings.TaskDeviceNumber[taskIndex] != taskdevicenumber) // change of device: cleanup old device and reset default settings
@@ -1844,7 +1853,7 @@ void handle_devices() {
if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) // if field set empty, reload defaults
PluginCall(PLUGIN_GET_DEVICEVALUENAMES, &TempEvent, dummyString); //the plugin should populate ExtraTaskSettings with its default values.
ClearCustomTaskSettings(taskIndex);
ClearCustomTaskSettings(taskIndex);
}
}
else if (taskdevicenumber != 0) //save settings
@@ -2121,13 +2130,16 @@ void handle_devices() {
addFormNote(F("This plugin is only supported on task 1-4 for now"));
}
addFormTextBox( F("Name"), F("TDN"), ExtraTaskSettings.TaskDeviceName, 40); //="taskdevicename"
addFormTextBox( F("Name"), F("TDN"), ExtraTaskSettings.TaskDeviceName, NAME_FORMULA_LENGTH_MAX); //="taskdevicename"
addFormCheckBox(F("Enabled"), F("TDE"), Settings.TaskDeviceEnabled[taskIndex]); //="taskdeviceenabled"
// section: Sensor / Actuator
if (!Device[DeviceIndex].Custom && Settings.TaskDeviceDataFeed[taskIndex] == 0 &&
((Device[DeviceIndex].Ports != 0) || (Device[DeviceIndex].PullUpOption) || (Device[DeviceIndex].InverseLogicOption) || (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)) )
((Device[DeviceIndex].Ports != 0) ||
(Device[DeviceIndex].PullUpOption) ||
(Device[DeviceIndex].InverseLogicOption) ||
(Device[DeviceIndex].connectedToGPIOpins())) )
{
addFormSubHeader((Device[DeviceIndex].SendDataOption) ? F("Sensor") : F("Actuator"));
@@ -2153,12 +2165,14 @@ void handle_devices() {
TempEvent.String3 = F("3rd GPIO");
PluginCall(PLUGIN_GET_DEVICEGPIONAMES, &TempEvent, dummyString);
if (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)
addFormPinSelect(TempEvent.String1, F("taskdevicepin1"), Settings.TaskDevicePin1[taskIndex]);
if (Device[DeviceIndex].Type >= DEVICE_TYPE_DUAL && Device[DeviceIndex].Type <= DEVICE_TYPE_TRIPLE)
addFormPinSelect( TempEvent.String2, F("taskdevicepin2"), Settings.TaskDevicePin2[taskIndex]);
if (Device[DeviceIndex].Type == DEVICE_TYPE_TRIPLE)
addFormPinSelect(TempEvent.String3, F("taskdevicepin3"), Settings.TaskDevicePin3[taskIndex]);
if (Device[DeviceIndex].connectedToGPIOpins()) {
if (Device[DeviceIndex].Type >= DEVICE_TYPE_SINGLE)
addFormPinSelect(TempEvent.String1, F("taskdevicepin1"), Settings.TaskDevicePin1[taskIndex]);
if (Device[DeviceIndex].Type >= DEVICE_TYPE_DUAL)
addFormPinSelect( TempEvent.String2, F("taskdevicepin2"), Settings.TaskDevicePin2[taskIndex]);
if (Device[DeviceIndex].Type == DEVICE_TYPE_TRIPLE)
addFormPinSelect(TempEvent.String3, F("taskdevicepin3"), Settings.TaskDevicePin3[taskIndex]);
}
}
//add plugins content
@@ -2242,14 +2256,14 @@ void handle_devices() {
TXBuffer += F("<TD>");
String id = F("TDVN"); //="taskdevicevaluename"
id += (varNr + 1);
addTextBox(id, ExtraTaskSettings.TaskDeviceValueNames[varNr], 40);
addTextBox(id, ExtraTaskSettings.TaskDeviceValueNames[varNr], NAME_FORMULA_LENGTH_MAX);
if (Device[DeviceIndex].FormulaOption)
{
TXBuffer += F("<TD>");
String id = F("TDF"); //="taskdeviceformula"
id += (varNr + 1);
addTextBox(id, ExtraTaskSettings.TaskDeviceFormula[varNr], 40);
addTextBox(id, ExtraTaskSettings.TaskDeviceFormula[varNr], NAME_FORMULA_LENGTH_MAX);
}
if (Device[DeviceIndex].FormulaOption || Device[DeviceIndex].DecimalsOnly)
+1
View File
@@ -255,6 +255,7 @@ static const char pgDefaultCSS[] PROGMEM = {
".div_br {clear: both; }"
// The alert message box
".alert {padding: 20px; background-color: #f44336; color: white; margin-bottom: 15px; }"
".warning {padding: 20px; background-color: #ffca17; color: white; margin-bottom: 15px; }"
// The close button
".closebtn {margin-left: 15px; color: white; font-weight: bold; float: right; font-size: 22px; line-height: 20px; cursor: pointer; transition: 0.3s; }"
// When moving the mouse over the close button
+1 -1
View File
@@ -100,7 +100,7 @@ boolean CPlugin_009(byte function, struct EventStruct *event, String& string)
// Each sensor value get an own object (0..n)
// sprintf(itemNames[x],"%d",x);
JsonObject& val = SENSOR.createNestedObject(String(x));
val[F("deviceName")] = ExtraTaskSettings.TaskDeviceName;
val[F("deviceName")] = getTaskDeviceName(event->TaskIndex);
val[F("valueName")] = ExtraTaskSettings.TaskDeviceValueNames[x];
val[F("type")] = event->sensorType;
val[F("value")] = formatUserVarNoCheck(event, x);
+3 -1
View File
@@ -117,7 +117,7 @@ void C013_SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskInde
infoReply.destTaskIndex = destTaskIndex;
LoadTaskSettings(infoReply.sourceTaskIndex);
infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex];
strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName);
strcpy(infoReply.taskName, getTaskDeviceName(infoReply.sourceTaskIndex).c_str());
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]);
@@ -228,6 +228,7 @@ void C013_Receive(struct EventStruct *event) {
// so it will write only once and has to be cleared manually through webgui
if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0)
{
taskClear(infoReply.destTaskIndex, false);
Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber;
Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed
for (byte x = 0; x < CONTROLLER_MAX; x++)
@@ -235,6 +236,7 @@ void C013_Receive(struct EventStruct *event) {
strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName);
for (byte x = 0; x < VARS_PER_TASK; x++)
strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]);
ExtraTaskSettings.TaskIndex = infoReply.destTaskIndex;
SaveTaskSettings(infoReply.destTaskIndex);
SaveSettings();
}
+25 -1
View File
@@ -27,6 +27,7 @@
#define PN532_COMMAND_INLISTPASSIVETARGET (0x4A)
#define PN532_RESPONSE_INLISTPASSIVETARGET (0x4B)
#define PN532_MIFARE_ISO14443A (0x00)
#define PN532_COMMAND_POWERDOWN (0x16)
uint8_t Plugin_017_pn532_packetbuffer[64];
uint8_t Plugin_017_command;
@@ -95,7 +96,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
static byte errorCount=0;
counter++;
if (counter == 3)
if (counter == 3 )
{
if (digitalRead(4) == 0 || digitalRead(5) == 0)
{
@@ -123,6 +124,7 @@ boolean Plugin_017(byte function, struct EventStruct *event, String& string)
Plugin_017_Init(Settings.TaskDevicePin3[event->TaskIndex]);
}
if (error == 0) {
unsigned long key = uid[0];
for (uint8_t i = 1; i < 4; i++) {
@@ -232,6 +234,23 @@ uint32_t getFirmwareVersion(void)
}
void Plugin_017_powerDown(void)
{
Plugin_017_pn532_packetbuffer[0] = PN532_COMMAND_POWERDOWN;
Plugin_017_pn532_packetbuffer[1] = 1 << 7; //allowed wakeup source is i2c
if (Plugin_017_writeCommand(Plugin_017_pn532_packetbuffer, 2)) {
return;
}
// delay(50); // we can try to read faster, but it will only put extra load on the I2C bus...
// read and ignore response
Plugin_017_readResponse(Plugin_017_pn532_packetbuffer, sizeof(Plugin_017_pn532_packetbuffer));
}
/*********************************************************************************************\
* PN532 read tag
\*********************************************************************************************/
@@ -273,6 +292,10 @@ byte Plugin_017_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t
uid[i] = Plugin_017_pn532_packetbuffer[6 + i];
}
// Plugin_017_Init(-1);
Plugin_017_powerDown();
return 0;
}
@@ -325,6 +348,7 @@ int16_t Plugin_017_readResponse(uint8_t buf[], uint8_t len)
if (!Wire.requestFrom(PN532_I2C_ADDRESS, len + 2))
return -1;
if (!(Wire.read() & 1))
return -1;
+12 -12
View File
@@ -23,12 +23,12 @@
#define PCA9685_ALLLED_REG (byte)0xFA
/*
is bit flag any bit rapresent the initialization state of PCA9685
is bit flag any bit rapresent the initialization state of PCA9685
es: bit 3 is set 1 PCA9685 with address 0X40 + 0x03 is intin
*/
#define IS_INIT(state, bit) ((state & 1 << bit) == 1 << bit)
#define SET_INIT(state, bit) (state|= 1 << bit)
long long initializeState; //
long long initializeState; //
boolean Plugin_022(byte function, struct EventStruct *event, String& string)
{
@@ -85,7 +85,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
Settings.TaskDevicePort[event->TaskIndex] = getFormItemInt(F("i2c_addr"));
success = true;
break;
}
}
case PLUGIN_WRITE:
{
@@ -100,7 +100,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
String name = line.substring(0,dotPos);
name.replace(F("["),F(""));
name.replace(F("]"),F(""));
if(name.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName) == true)
if(name.equalsIgnoreCase(getTaskDeviceName(event->TaskIndex)) == true)
{
line = line.substring(dotPos + 1);
istanceCommand = true;
@@ -121,7 +121,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
if(event->Par2 >=0 && event->Par2 <= PCA9685_MAX_PWM)
{
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS))) Plugin_022_initialize(address);
Plugin_022_Write(address, event->Par1, event->Par2);
setPinState(PLUGIN_ID_022, event->Par1, PIN_MODE_PWM, event->Par2);
addLog(LOG_LEVEL_INFO, log);
@@ -139,7 +139,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
{
success = true;
if(event->Par1 >= PCA9685_MIN_FREQUENCY && event->Par1 <= PCA9685_MAX_FREQUENCY)
{
{
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS))) Plugin_022_initialize(address);
Plugin_022_Frequency(address, event->Par1);
@@ -150,7 +150,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
}
else{
addLog(LOG_LEVEL_ERROR,String(F("PCA ")) + String(address, HEX) + String(F(" The frequesncy ")) + String(event->Par1) + String(F(" is out of range.")));
}
}
}
@@ -175,7 +175,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
if(parseString(line,2) == "all")
{
pin = -1;
log += String(F("all"));
log += String(F("all"));
}
else
{
@@ -189,10 +189,10 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
else
{
log += F(" on");
Plugin_022_On(address, pin);
Plugin_022_On(address, pin);
}
addLog(LOG_LEVEL_INFO, log);
setPinState(PLUGIN_ID_022, pin, PIN_MODE_OUTPUT, event->Par2);
setPinState(PLUGIN_ID_022, pin, PIN_MODE_OUTPUT, event->Par2);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, pin, log, 0));
}
else{
@@ -237,7 +237,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
log += String(autoreset);
}
}
}
setSystemTimer(event->Par3 , PLUGIN_ID_022
, event->TaskIndex
@@ -286,7 +286,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
, autoreset);
}
setPinState(PLUGIN_ID_022, event->Par1, PIN_MODE_OUTPUT, event->Par2);
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par1, log, 0));
SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par1, log, 0));
break;
}
}
+4 -4
View File
@@ -235,7 +235,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
String name = arguments.substring(0,dotPos);
name.replace(F("["),F(""));
name.replace(F("]"),F(""));
if(name.equalsIgnoreCase(ExtraTaskSettings.TaskDeviceName) == true)
if(name.equalsIgnoreCase(getTaskDeviceName(event->TaskIndex)) == true)
{
arguments = arguments.substring(dotPos+1);
}
@@ -244,7 +244,7 @@ boolean Plugin_023(byte function, struct EventStruct *event, String& string)
return false;
}
}
int argIndex = arguments.indexOf(',');
if (argIndex)
arguments = arguments.substring(0, argIndex);
@@ -492,7 +492,7 @@ void Plugin_023_reset_display(struct Plugin_023_OLED_SettingStruct &oled)
void Plugin_023_StartUp_OLED(struct Plugin_023_OLED_SettingStruct &oled)
{
{
Plugin_023_init_OLED(oled);
Plugin_023_reset_display(oled);
Plugin_023_displayOff(oled);
@@ -644,7 +644,7 @@ void Plugin_023_init_OLED(struct Plugin_023_OLED_SettingStruct &oled)
multiplex = 0x3F;
compins = 0x12;
}
Plugin_023_sendcommand(address, 0xAE); //display off
Plugin_023_sendcommand(address, 0xD5); //SETDISPLAYCLOCKDIV
Plugin_023_sendcommand(address, 0x80); // the suggested ratio 0x80
+4 -4
View File
@@ -200,7 +200,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
log = F("ERR : Illegal Payload ");
log += Payload;
log += " ";
log += ExtraTaskSettings.TaskDeviceName;
log += getTaskDeviceName(event->TaskIndex);
addLog(LOG_LEVEL_INFO, log);
success = false;
break;
@@ -227,7 +227,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
// Log the event
String log = F("IMPT : [");
log += ExtraTaskSettings.TaskDeviceName;
log += getTaskDeviceName(event->TaskIndex);
log += F("#");
log += ExtraTaskSettings.TaskDeviceValueNames[x];
log += F("] : ");
@@ -239,7 +239,7 @@ boolean Plugin_037(byte function, struct EventStruct *event, String& string)
if (Settings.UseRules)
{
String RuleEvent = F("");
RuleEvent += ExtraTaskSettings.TaskDeviceName;
RuleEvent += getTaskDeviceName(event->TaskIndex);
RuleEvent += F("#");
RuleEvent += ExtraTaskSettings.TaskDeviceValueNames[x];
RuleEvent += F("=");
@@ -287,7 +287,7 @@ boolean MQTTSubscribe_037()
{
String log = F("IMPT : [");
LoadTaskSettings(y);
log += ExtraTaskSettings.TaskDeviceName;
log += getTaskDeviceName(y);
log += F("#");
log += ExtraTaskSettings.TaskDeviceValueNames[x];
log += F("] subscribed to ");
+1 -1
View File
@@ -317,7 +317,7 @@ boolean Plugin_044(byte function, struct EventStruct *event, String& string)
if (Settings.UseRules)
{
LoadTaskSettings(event->TaskIndex);
String eventString = ExtraTaskSettings.TaskDeviceName;
String eventString = getTaskDeviceName(event->TaskIndex);
eventString += F("#Data");
rulesProcessing(eventString);
}
+8
View File
@@ -1241,10 +1241,18 @@ byte PluginCall(byte Function, struct EventStruct *event, String& str)
// Schedule the plugin to be read.
schedule_task_device_timer_at_init(event->TaskIndex);
}
if (Function != PLUGIN_GET_DEVICEVALUENAMES) {
// LoadTaskSettings may call PLUGIN_GET_DEVICEVALUENAMES.
LoadTaskSettings(event->TaskIndex);
}
event->BaseVarIndex = event->TaskIndex * VARS_PER_TASK;
checkRAM(F("PluginCall_init"),x);
START_TIMER;
bool retval = Plugin_ptr[x](Function, event, str);
if (Function == PLUGIN_GET_DEVICEVALUENAMES) {
ExtraTaskSettings.TaskIndex = event->TaskIndex;
}
STOP_TIMER_TASK(x,Function);
return retval;
}