Same procedure. setoption65 1 is a working workaround to avoid a crash on starting the device when there is a frequency of 100Hz or higher on one counter. The change temporarily disables the counter during the access to the flash. I', currently not sure if this is an ESP8266 only problem or also an ESP32 problem that the interrupt of the counter and flash access could cause a crash.
1524 lines
56 KiB
C++
1524 lines
56 KiB
C++
/*
|
|
settings.ino - user settings for Tasmota
|
|
|
|
Copyright (C) 2021 Theo Arends
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*********************************************************************************************\
|
|
* RTC memory
|
|
\*********************************************************************************************/
|
|
|
|
const uint16_t RTC_MEM_VALID = 0xA55A;
|
|
|
|
uint32_t rtc_settings_crc = 0;
|
|
|
|
uint32_t GetRtcSettingsCrc(void) {
|
|
uint32_t crc = 0;
|
|
uint8_t *bytes = (uint8_t*)&RtcSettings;
|
|
|
|
for (uint32_t i = 0; i < sizeof(RtcSettings); i++) {
|
|
crc += bytes[i]*(i+1);
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
void RtcSettingsSave(void) {
|
|
RtcSettings.baudrate = Settings->baudrate * 300;
|
|
if (GetRtcSettingsCrc() != rtc_settings_crc) {
|
|
|
|
if (RTC_MEM_VALID != RtcSettings.valid) {
|
|
memset(&RtcSettings, 0, sizeof(RtcSettings));
|
|
RtcSettings.valid = RTC_MEM_VALID;
|
|
RtcSettings.energy_kWhtoday = Settings->energy_kWhtoday;
|
|
RtcSettings.energy_kWhtotal = Settings->energy_kWhtotal;
|
|
for (uint32_t i = 0; i < 3; i++) {
|
|
RtcSettings.energy_kWhtoday_ph[i] = Settings->energy_kWhtoday_ph[i];
|
|
RtcSettings.energy_kWhtotal_ph[i] = Settings->energy_kWhtotal_ph[i];
|
|
}
|
|
RtcSettings.energy_usage = Settings->energy_usage;
|
|
for (uint32_t i = 0; i < MAX_COUNTERS; i++) {
|
|
RtcSettings.pulse_counter[i] = Settings->pulse_counter[i];
|
|
}
|
|
RtcSettings.power = Settings->power;
|
|
// RtcSettings.baudrate = Settings->baudrate * 300;
|
|
RtcSettings.baudrate = APP_BAUDRATE;
|
|
}
|
|
|
|
#ifdef ESP8266
|
|
ESP.rtcUserMemoryWrite(100, (uint32_t*)&RtcSettings, sizeof(RtcSettings));
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
RtcDataSettings = RtcSettings;
|
|
#endif // ESP32
|
|
|
|
rtc_settings_crc = GetRtcSettingsCrc();
|
|
}
|
|
}
|
|
|
|
bool RtcSettingsLoad(uint32_t update) {
|
|
#ifdef ESP8266
|
|
ESP.rtcUserMemoryRead(100, (uint32_t*)&RtcSettings, sizeof(RtcSettings)); // 0x290
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
RtcSettings = RtcDataSettings;
|
|
#endif // ESP32
|
|
|
|
bool read_valid = (RTC_MEM_VALID == RtcSettings.valid);
|
|
if (update) {
|
|
if (!read_valid) {
|
|
RtcSettingsSave();
|
|
}
|
|
}
|
|
return read_valid;
|
|
}
|
|
|
|
bool RtcSettingsValid(void) {
|
|
return (RTC_MEM_VALID == RtcSettings.valid);
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
uint32_t rtc_reboot_crc = 0;
|
|
|
|
uint32_t GetRtcRebootCrc(void) {
|
|
uint32_t crc = 0;
|
|
uint8_t *bytes = (uint8_t*)&RtcReboot;
|
|
|
|
for (uint32_t i = 0; i < sizeof(RtcReboot); i++) {
|
|
crc += bytes[i]*(i+1);
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
void RtcRebootSave(void) {
|
|
if (GetRtcRebootCrc() != rtc_reboot_crc) {
|
|
RtcReboot.valid = RTC_MEM_VALID;
|
|
#ifdef ESP8266
|
|
ESP.rtcUserMemoryWrite(100 - sizeof(RtcReboot), (uint32_t*)&RtcReboot, sizeof(RtcReboot));
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
RtcDataReboot = RtcReboot;
|
|
#endif // ESP32
|
|
rtc_reboot_crc = GetRtcRebootCrc();
|
|
}
|
|
}
|
|
|
|
void RtcRebootReset(void) {
|
|
RtcReboot.fast_reboot_count = 0;
|
|
RtcRebootSave();
|
|
}
|
|
|
|
void RtcRebootLoad(void) {
|
|
#ifdef ESP8266
|
|
ESP.rtcUserMemoryRead(100 - sizeof(RtcReboot), (uint32_t*)&RtcReboot, sizeof(RtcReboot)); // 0x280
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
RtcReboot = RtcDataReboot;
|
|
#endif // ESP32
|
|
if (RtcReboot.valid != RTC_MEM_VALID) {
|
|
memset(&RtcReboot, 0, sizeof(RtcReboot));
|
|
RtcReboot.valid = RTC_MEM_VALID;
|
|
// RtcReboot.fast_reboot_count = 0; // Explicit by memset
|
|
RtcRebootSave();
|
|
}
|
|
rtc_reboot_crc = GetRtcRebootCrc();
|
|
}
|
|
|
|
bool RtcRebootValid(void) {
|
|
return (RTC_MEM_VALID == RtcReboot.valid);
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
* ESP8266 Tasmota Flash usage offset from 0x40200000
|
|
*
|
|
* Tasmota 1M Tasmota 2M Tasmota 4M - Flash usage
|
|
* 0x00000000 - 4k Unzipped binary bootloader
|
|
* 0x00000FFF
|
|
*
|
|
* 0x00001000 - Unzipped binary code start
|
|
* ::::
|
|
* 0x000xxxxx - Unzipped binary code end
|
|
* 0x000x1000 - First page used by Core OTA
|
|
* ::::
|
|
* 0x000F2FFF 0x000F5FFF 0x000F5FFF
|
|
******************************************************************************
|
|
* Next 32k is overwritten by OTA
|
|
* 0x000F3000 0x000F6000 0x000F6000 - 4k Tasmota Quick Power Cycle counter (SETTINGS_LOCATION - CFG_ROTATES) - First four bytes only
|
|
* 0x000F3FFF 0x000F6FFF 0x000F6FFF
|
|
* 0x000F4000 0x000F7000 0x000F7000 - 4k First Tasmota rotating settings page
|
|
* ::::
|
|
* 0x000FA000 0x000FD000 0x000FD000 - 4k Last Tasmota rotating settings page = Last page used by Core OTA (SETTINGS_LOCATION)
|
|
* 0x000FAFFF 0x000FDFFF 0x000FDFFF
|
|
******************************************************************************
|
|
* 0x000FE000 0x000FE000 - 3k9 Not used
|
|
* 0x000FEFF0 0x000FEFF0 - 4k1 Empty
|
|
* 0x000FFFFF 0x000FFFFF
|
|
*
|
|
* 0x000FB000 0x00100000 0x00100000 - 0k, 980k or 2980k Core FS start (LittleFS)
|
|
* 0x000FB000 0x001FA000 0x003FA000 - 0k, 980k or 2980k Core FS end (LittleFS)
|
|
* 0x001FAFFF 0x003FAFFF
|
|
*
|
|
* 0x000FB000 0x001FB000 0x003FB000 - 4k Core EEPROM = Tasmota settings page during OTA and when no flash rotation is active (EEPROM_LOCATION)
|
|
* 0x000FBFFF 0x001FBFFF 0x003FBFFF
|
|
*
|
|
* 0x000FC000 0x001FC000 0x003FC000 - 4k SDK - Uses first 128 bytes for phy init data mirrored by Core in RAM. See core_esp8266_phy.cpp phy_init_data[128] = Core user_rf_cal_sector
|
|
* 0x000FD000 0x001FD000 0x003FD000 - 4k SDK - Uses scattered bytes from 0x340 (iTead use as settings storage from 0x000FD000)
|
|
* 0x000FE000 0x001FE000 0x003FE000 - 4k SDK - Uses scattered bytes from 0x340 (iTead use as mirrored settings storage from 0x000FE000)
|
|
* 0x000FF000 0x001FF000 0x0031F000 - 4k SDK - Uses at least first 32 bytes of this page - Tasmota Zigbee persistence from 0x000FF800 to 0x000FFFFF
|
|
* 0x000FFFFF 0x001FFFFF 0x003FFFFF
|
|
\*********************************************************************************************/
|
|
|
|
extern "C" {
|
|
#include "spi_flash.h"
|
|
}
|
|
|
|
#ifdef ESP8266
|
|
|
|
#include "eboot_command.h"
|
|
|
|
extern "C" uint32_t _FS_start; // 1M = 0x402fb000, 2M = 0x40300000, 4M = 0x40300000
|
|
const uint32_t FLASH_FS_START = (((uint32_t)&_FS_start - 0x40200000) / SPI_FLASH_SEC_SIZE);
|
|
uint32_t SETTINGS_LOCATION = FLASH_FS_START -1; // 0xFA, 0x0FF or 0x0FF
|
|
|
|
// From libraries/EEPROM/EEPROM.cpp EEPROMClass
|
|
extern "C" uint32_t _EEPROM_start; // 1M = 0x402FB000, 2M = 0x403FB000, 4M = 0x405FB000
|
|
const uint32_t EEPROM_LOCATION = ((uint32_t)&_EEPROM_start - 0x40200000) / SPI_FLASH_SEC_SIZE; // 0xFB, 0x1FB or 0x3FB
|
|
|
|
#endif // ESP8266
|
|
|
|
#ifdef ESP32
|
|
|
|
// dummy defines
|
|
#define EEPROM_LOCATION (SPI_FLASH_SEC_SIZE * 200)
|
|
uint32_t SETTINGS_LOCATION = EEPROM_LOCATION;
|
|
|
|
#endif // ESP32
|
|
|
|
const uint8_t CFG_ROTATES = 7; // Number of flash sectors used (handles uploads)
|
|
|
|
uint32_t settings_location = EEPROM_LOCATION;
|
|
uint32_t settings_crc32 = 0;
|
|
uint8_t *settings_buffer = nullptr;
|
|
uint8_t config_xor_on_set = CONFIG_FILE_XOR;
|
|
|
|
void SettingsInit(void) {
|
|
if (SETTINGS_LOCATION > 0xFA) {
|
|
SETTINGS_LOCATION = 0xFD; // Skip empty partition part and keep in first 1M
|
|
}
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
* Quick power cycle monitoring
|
|
\*********************************************************************************************/
|
|
|
|
void UpdateQuickPowerCycle(bool update) {
|
|
#ifndef FIRMWARE_MINIMAL
|
|
if (Settings->flag3.fast_power_cycle_disable) { return; } // SetOption65 - Disable fast power cycle detection for device reset
|
|
|
|
const uint32_t QPC_COUNT = 7; // Number of Power Cycles before Settings erase
|
|
const uint32_t QPC_SIGNATURE = 0xFFA55AFF;
|
|
#ifdef USE_COUNTER
|
|
CounterInterruptDisable(true);
|
|
#endif
|
|
#ifdef ESP8266
|
|
const uint32_t qpc_sector = SETTINGS_LOCATION - CFG_ROTATES;
|
|
const uint32_t qpc_location = qpc_sector * SPI_FLASH_SEC_SIZE;
|
|
|
|
uint32_t qpc_buffer[QPC_COUNT +1];
|
|
ESP.flashRead(qpc_location, (uint32*)&qpc_buffer, sizeof(qpc_buffer));
|
|
if (update && (QPC_SIGNATURE == qpc_buffer[0])) {
|
|
uint32_t counter = 1;
|
|
while ((0 == qpc_buffer[counter]) && (counter <= QPC_COUNT)) { counter++; }
|
|
if (QPC_COUNT == counter) { // 7 power cycles in a row
|
|
SettingsErase(3); // Quickly reset all settings including QuickPowerCycle flag
|
|
EspRestart(); // And restart
|
|
} else {
|
|
qpc_buffer[0] = 0;
|
|
ESP.flashWrite(qpc_location + (counter * 4), (uint32*)&qpc_buffer, 4);
|
|
AddLog(LOG_LEVEL_INFO, PSTR("QPC: Count %d"), counter);
|
|
}
|
|
}
|
|
else if ((qpc_buffer[0] != QPC_SIGNATURE) || (0 == qpc_buffer[1])) {
|
|
qpc_buffer[0] = QPC_SIGNATURE;
|
|
// Assume flash is default all ones and setting a bit to zero does not need an erase
|
|
if (ESP.flashEraseSector(qpc_sector)) {
|
|
ESP.flashWrite(qpc_location, (uint32*)&qpc_buffer, 4);
|
|
AddLog(LOG_LEVEL_INFO, PSTR("QPC: Reset"));
|
|
}
|
|
}
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
uint32_t pc_register;
|
|
QPCRead(&pc_register, sizeof(pc_register));
|
|
if (update && ((pc_register & 0xFFFFFFF0) == 0xFFA55AF0)) {
|
|
uint32_t counter = pc_register & 0xF; // Allow up to 15 cycles
|
|
if (0xF == counter) { counter = 0; }
|
|
counter++;
|
|
if (QPC_COUNT == counter) { // 7 power cycles in a row
|
|
SettingsErase(3); // Quickly reset all settings including QuickPowerCycle flag
|
|
EspRestart(); // And restart
|
|
} else {
|
|
pc_register = 0xFFA55AF0 | counter;
|
|
QPCWrite(&pc_register, sizeof(pc_register));
|
|
AddLog(LOG_LEVEL_INFO, PSTR("QPC: Count %d"), counter);
|
|
}
|
|
}
|
|
else if (pc_register != QPC_SIGNATURE) {
|
|
pc_register = QPC_SIGNATURE;
|
|
QPCWrite(&pc_register, sizeof(pc_register));
|
|
AddLog(LOG_LEVEL_INFO, PSTR("QPC: Reset"));
|
|
}
|
|
#endif // ESP32
|
|
#ifdef USE_COUNTER
|
|
CounterInterruptDisable(false);
|
|
#endif
|
|
#endif // FIRMWARE_MINIMAL
|
|
}
|
|
#ifdef USE_EMERGENCY_RESET
|
|
/*********************************************************************************************\
|
|
* Emergency reset if Rx and Tx are tied together
|
|
\*********************************************************************************************/
|
|
|
|
void EmergencyReset(void) {
|
|
Serial.begin(115200);
|
|
Serial.write(0xA5);
|
|
Serial.write(0x5A);
|
|
delay(1);
|
|
if (Serial.available() == 2) {
|
|
if ((Serial.read() == 0xA5) && (Serial.read() == 0x5A)) {
|
|
SettingsErase(3); // Reset all settings including QuickPowerCycle flag
|
|
|
|
do { // Wait for user to remove Rx Tx jumper and power cycle
|
|
Serial.write(0xA5);
|
|
delay(1000); // Satisfy SDK
|
|
} while (Serial.read() == 0xA5); // Poll for removal of jumper
|
|
|
|
ESP_Restart(); // Restart to init default settings
|
|
}
|
|
}
|
|
Serial.println();
|
|
Serial.flush();
|
|
#ifdef ESP32
|
|
delay(10); // Allow time to cleanup queues - if not used hangs ESP32
|
|
Serial.end();
|
|
delay(10); // Allow time to cleanup queues - if not used hangs ESP32
|
|
#endif // ESP32
|
|
}
|
|
#endif // USE_EMERGENCY_RESET
|
|
|
|
/*********************************************************************************************\
|
|
* Settings services
|
|
\*********************************************************************************************/
|
|
|
|
uint16_t GetCfgCrc16(uint8_t *bytes, uint32_t size) {
|
|
uint16_t crc = 0;
|
|
|
|
for (uint32_t i = 0; i < size; i++) {
|
|
if ((i < 14) || (i > 15)) { crc += bytes[i]*(i+1); } // Skip crc
|
|
}
|
|
return crc;
|
|
}
|
|
|
|
uint16_t GetSettingsCrc(void) {
|
|
// Fix miscalculation if previous Settings was 3584 and current Settings is 4096 between 0x06060007 and 0x0606000A
|
|
uint32_t size = ((Settings->version < 0x06060007) || (Settings->version > 0x0606000A)) ? 3584 : sizeof(TSettings);
|
|
return GetCfgCrc16((uint8_t*)Settings, size);
|
|
}
|
|
|
|
uint32_t GetCfgCrc32(uint8_t *bytes, uint32_t size) {
|
|
// https://create.stephan-brumme.com/crc32/#bitwise
|
|
uint32_t crc = 0;
|
|
|
|
while (size--) {
|
|
crc ^= *bytes++;
|
|
for (uint32_t j = 0; j < 8; j++) {
|
|
crc = (crc >> 1) ^ (-int(crc & 1) & 0xEDB88320);
|
|
}
|
|
}
|
|
return ~crc;
|
|
}
|
|
|
|
uint32_t GetSettingsCrc32(void) {
|
|
return GetCfgCrc32((uint8_t*)Settings, sizeof(TSettings) -4); // Skip crc32
|
|
}
|
|
|
|
void SettingsSaveAll(void) {
|
|
if (Settings->flag.save_state) {
|
|
Settings->power = TasmotaGlobal.power;
|
|
} else {
|
|
Settings->power = 0;
|
|
}
|
|
XsnsCall(FUNC_SAVE_BEFORE_RESTART);
|
|
XdrvCall(FUNC_SAVE_BEFORE_RESTART);
|
|
SettingsSave(0);
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
* Settings backup and restore
|
|
\*********************************************************************************************/
|
|
|
|
void SettingsBufferFree(void) {
|
|
if (settings_buffer != nullptr) {
|
|
free(settings_buffer);
|
|
settings_buffer = nullptr;
|
|
}
|
|
}
|
|
|
|
bool SettingsBufferAlloc(void) {
|
|
SettingsBufferFree();
|
|
if (!(settings_buffer = (uint8_t *)malloc(sizeof(TSettings)))) {
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION D_UPLOAD_ERR_2)); // Not enough (memory) space
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
String SettingsConfigFilename(void) {
|
|
char filename[TOPSZ];
|
|
char hostname[sizeof(TasmotaGlobal.hostname)];
|
|
snprintf_P(filename, sizeof(filename), PSTR("Config_%s_%s.dmp"), NoAlNumToUnderscore(hostname, TasmotaGlobal.hostname), TasmotaGlobal.version);
|
|
return String(filename);
|
|
}
|
|
|
|
uint32_t SettingsConfigBackup(void) {
|
|
if (!SettingsBufferAlloc()) { return 0; }
|
|
|
|
uint32_t cfg_crc32 = Settings->cfg_crc32;
|
|
Settings->cfg_crc32 = GetSettingsCrc32(); // Calculate crc (again) as it might be wrong when savedata = 0 (#3918)
|
|
|
|
uint32_t config_len = sizeof(TSettings);
|
|
memcpy(settings_buffer, Settings, config_len);
|
|
|
|
Settings->cfg_crc32 = cfg_crc32; // Restore crc in case savedata = 0 to make sure settings will be noted as changed
|
|
|
|
if (config_xor_on_set) {
|
|
for (uint32_t i = 2; i < config_len; i++) {
|
|
settings_buffer[i] ^= (config_xor_on_set +i);
|
|
}
|
|
}
|
|
return config_len;
|
|
}
|
|
|
|
bool SettingsConfigRestore(void) {
|
|
uint32_t config_len = sizeof(TSettings);
|
|
|
|
if (config_xor_on_set) {
|
|
for (uint32_t i = 2; i < config_len; i++) {
|
|
settings_buffer[i] ^= (config_xor_on_set +i);
|
|
}
|
|
}
|
|
|
|
bool valid_settings = false;
|
|
|
|
// unsigned long version; // 008
|
|
unsigned long buffer_version = settings_buffer[11] << 24 | settings_buffer[10] << 16 | settings_buffer[9] << 8 | settings_buffer[8];
|
|
if (buffer_version > 0x06000000) {
|
|
// uint16_t cfg_size; // 002
|
|
uint32_t buffer_size = settings_buffer[3] << 8 | settings_buffer[2];
|
|
if (buffer_version > 0x0606000A) {
|
|
// uint32_t cfg_crc32; // FFC
|
|
uint32_t buffer_crc32 = settings_buffer[4095] << 24 | settings_buffer[4094] << 16 | settings_buffer[4093] << 8 | settings_buffer[4092];
|
|
valid_settings = (GetCfgCrc32(settings_buffer, buffer_size -4) == buffer_crc32);
|
|
} else {
|
|
// uint16_t cfg_crc; // 00E
|
|
uint16_t buffer_crc16 = settings_buffer[15] << 8 | settings_buffer[14];
|
|
valid_settings = (GetCfgCrc16(settings_buffer, buffer_size) == buffer_crc16);
|
|
}
|
|
} else {
|
|
valid_settings = (settings_buffer[0] == CONFIG_FILE_SIGN);
|
|
}
|
|
|
|
if (valid_settings) {
|
|
// uint8_t config_version; // F36
|
|
#ifdef ESP8266
|
|
valid_settings = (0 == settings_buffer[0xF36]); // Settings->config_version
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
|
|
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
|
valid_settings = (2 == settings_buffer[0xF36]); // Settings->config_version ESP32S3
|
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
valid_settings = (3 == settings_buffer[0xF36]); // Settings->config_version ESP32S2
|
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
valid_settings = (4 == settings_buffer[0xF36]); // Settings->config_version ESP32C3
|
|
#else
|
|
valid_settings = (1 == settings_buffer[0xF36]); // Settings->config_version ESP32 all other
|
|
#endif // CONFIG_IDF_TARGET_ESP32S3
|
|
#endif // ESP32
|
|
}
|
|
|
|
if (valid_settings) {
|
|
SettingsDefaultSet2();
|
|
memcpy((char*)Settings +16, settings_buffer +16, config_len -16);
|
|
Settings->version = buffer_version; // Restore version and auto upgrade after restart
|
|
}
|
|
|
|
SettingsBufferFree();
|
|
|
|
return valid_settings;
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
* Config Settings->text char array support
|
|
\*********************************************************************************************/
|
|
|
|
uint32_t GetSettingsTextLen(void) {
|
|
char* position = Settings->text_pool;
|
|
for (uint32_t size = 0; size < SET_MAX; size++) {
|
|
while (*position++ != '\0') { }
|
|
}
|
|
return position - Settings->text_pool;
|
|
}
|
|
|
|
bool settings_text_mutex = false;
|
|
uint32_t settings_text_busy_count = 0;
|
|
|
|
bool SettingsUpdateFinished(void) {
|
|
uint32_t wait_loop = 10;
|
|
while (settings_text_mutex && wait_loop) { // Wait for any update to finish
|
|
yield();
|
|
delayMicroseconds(1);
|
|
wait_loop--;
|
|
}
|
|
return (wait_loop > 0); // true if finished
|
|
}
|
|
|
|
bool SettingsUpdateText(uint32_t index, const char* replace_me) {
|
|
if (index >= SET_MAX) {
|
|
return false; // Setting not supported - internal error
|
|
}
|
|
|
|
// Make a copy first in case we use source from Settings->text
|
|
uint32_t replace_len = strlen_P(replace_me);
|
|
char replace[replace_len +1];
|
|
memcpy_P(replace, replace_me, sizeof(replace));
|
|
uint32_t index_save = index;
|
|
|
|
uint32_t start_pos = 0;
|
|
uint32_t end_pos = 0;
|
|
char* position = Settings->text_pool;
|
|
for (uint32_t size = 0; size < SET_MAX; size++) {
|
|
while (*position++ != '\0') { }
|
|
if (1 == index) {
|
|
start_pos = position - Settings->text_pool;
|
|
}
|
|
else if (0 == index) {
|
|
end_pos = position - Settings->text_pool -1;
|
|
}
|
|
index--;
|
|
}
|
|
uint32_t char_len = position - Settings->text_pool;
|
|
|
|
uint32_t current_len = end_pos - start_pos;
|
|
int diff = replace_len - current_len;
|
|
|
|
// AddLog(LOG_LEVEL_DEBUG, PSTR("TST: start %d, end %d, len %d, current %d, replace %d, diff %d"),
|
|
// start_pos, end_pos, char_len, current_len, replace_len, diff);
|
|
|
|
int too_long = (char_len + diff) - settings_text_size;
|
|
if (too_long > 0) {
|
|
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_CONFIG "Text overflow by %d char(s)"), too_long);
|
|
return false; // Replace text too long
|
|
}
|
|
|
|
if (settings_text_mutex && !SettingsUpdateFinished()) {
|
|
settings_text_busy_count++;
|
|
} else {
|
|
settings_text_mutex = true;
|
|
|
|
if (diff != 0) {
|
|
// Shift Settings->text up or down
|
|
memmove_P(Settings->text_pool + start_pos + replace_len, Settings->text_pool + end_pos, char_len - end_pos);
|
|
}
|
|
// Replace text
|
|
memmove_P(Settings->text_pool + start_pos, replace, replace_len);
|
|
// Fill for future use
|
|
memset(Settings->text_pool + char_len + diff, 0x00, settings_text_size - char_len - diff);
|
|
|
|
settings_text_mutex = false;
|
|
}
|
|
|
|
#ifdef DEBUG_FUNC_SETTINGSUPDATETEXT
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "CR %d/%d, Busy %d, Id %02d = \"%s\""), GetSettingsTextLen(), settings_text_size, settings_text_busy_count, index_save, replace);
|
|
#else
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "CR %d/%d, Busy %d"), GetSettingsTextLen(), settings_text_size, settings_text_busy_count);
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
char* SettingsText(uint32_t index) {
|
|
char* position = Settings->text_pool;
|
|
|
|
if (index >= SET_MAX) {
|
|
position += settings_text_size -1; // Setting not supported - internal error - return empty string
|
|
} else {
|
|
SettingsUpdateFinished();
|
|
for (;index > 0; index--) {
|
|
while (*position++ != '\0') { }
|
|
}
|
|
}
|
|
return position;
|
|
}
|
|
|
|
/*********************************************************************************************\
|
|
* Config Save - Save parameters to Flash ONLY if any parameter has changed
|
|
\*********************************************************************************************/
|
|
|
|
void UpdateBackwardCompatibility(void) {
|
|
// Perform updates for backward compatibility
|
|
strlcpy(Settings->user_template_name, SettingsText(SET_TEMPLATE_NAME), sizeof(Settings->user_template_name));
|
|
}
|
|
|
|
uint32_t GetSettingsAddress(void) {
|
|
return settings_location * SPI_FLASH_SEC_SIZE;
|
|
}
|
|
|
|
void SettingsSave(uint8_t rotate) {
|
|
/* Save configuration in eeprom or one of 7 slots below
|
|
*
|
|
* rotate 0 = Save in next flash slot
|
|
* rotate 1 = Save only in eeprom flash slot until SetOption12 0 or restart
|
|
* rotate 2 = Save in eeprom flash slot, erase next flash slots and continue depending on stop_flash_rotate
|
|
* stop_flash_rotate 0 = Allow flash slot rotation (SetOption12 0)
|
|
* stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1)
|
|
*/
|
|
#ifndef FIRMWARE_MINIMAL
|
|
XsnsCall(FUNC_SAVE_SETTINGS);
|
|
XdrvCall(FUNC_SAVE_SETTINGS);
|
|
UpdateBackwardCompatibility();
|
|
if ((GetSettingsCrc32() != settings_crc32) || rotate) {
|
|
if (1 == rotate) { // Use eeprom flash slot only and disable flash rotate from now on (upgrade)
|
|
TasmotaGlobal.stop_flash_rotate = 1;
|
|
}
|
|
|
|
if (TasmotaGlobal.stop_flash_rotate || (2 == rotate)) { // Use eeprom flash slot and erase next flash slots if stop_flash_rotate is off (default)
|
|
settings_location = EEPROM_LOCATION;
|
|
} else { // Rotate flash slots
|
|
if (settings_location == EEPROM_LOCATION) {
|
|
settings_location = SETTINGS_LOCATION;
|
|
} else {
|
|
settings_location--;
|
|
}
|
|
if (settings_location <= (SETTINGS_LOCATION - CFG_ROTATES)) {
|
|
settings_location = EEPROM_LOCATION;
|
|
}
|
|
}
|
|
|
|
Settings->save_flag++;
|
|
if (UtcTime() > START_VALID_TIME) {
|
|
Settings->cfg_timestamp = UtcTime();
|
|
} else {
|
|
Settings->cfg_timestamp++;
|
|
}
|
|
Settings->cfg_size = sizeof(TSettings);
|
|
Settings->cfg_crc = GetSettingsCrc(); // Keep for backward compatibility in case of fall-back just after upgrade
|
|
Settings->cfg_crc32 = GetSettingsCrc32();
|
|
#ifdef USE_COUNTER
|
|
CounterInterruptDisable(true);
|
|
#endif
|
|
#ifdef ESP8266
|
|
#ifdef USE_UFILESYS
|
|
TfsSaveFile(TASM_FILE_SETTINGS, (const uint8_t*)Settings, sizeof(TSettings));
|
|
#endif // USE_UFILESYS
|
|
if (ESP.flashEraseSector(settings_location)) {
|
|
ESP.flashWrite(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)Settings, sizeof(TSettings));
|
|
}
|
|
|
|
if (!TasmotaGlobal.stop_flash_rotate && rotate) { // SetOption12 - (Settings) Switch between dynamic (0) or fixed (1) slot flash save location
|
|
for (uint32_t i = 0; i < CFG_ROTATES; i++) {
|
|
ESP.flashEraseSector(SETTINGS_LOCATION -i); // Delete previous configurations by resetting to 0xFF
|
|
delay(1);
|
|
}
|
|
}
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG D_SAVED_TO_FLASH_AT " %X, " D_COUNT " %d, " D_BYTES " %d"), settings_location, Settings->save_flag, sizeof(TSettings));
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
SettingsWrite(Settings, sizeof(TSettings));
|
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_CONFIG "Saved, " D_COUNT " %d, " D_BYTES " %d"), Settings->save_flag, sizeof(TSettings));
|
|
#endif // ESP32
|
|
|
|
settings_crc32 = Settings->cfg_crc32;
|
|
}
|
|
#endif // FIRMWARE_MINIMAL
|
|
RtcSettingsSave();
|
|
#ifdef USE_COUNTER
|
|
CounterInterruptDisable(false);
|
|
#endif
|
|
}
|
|
void SettingsLoad(void) {
|
|
#ifdef ESP8266
|
|
// Load configuration from optional file and flash (eeprom and 7 additonal slots) if first valid load does not stop_flash_rotate
|
|
// Activated with version 8.4.0.2 - Fails to read any config before version 6.6.0.11
|
|
settings_location = 0;
|
|
uint32_t save_flag = 0;
|
|
uint32_t max_slots = CFG_ROTATES +1;
|
|
uint32_t flash_location;
|
|
uint32_t slot = 1;
|
|
#ifdef USE_UFILESYS
|
|
if (TfsLoadFile(TASM_FILE_SETTINGS, (uint8_t*)Settings, sizeof(TSettings))) {
|
|
flash_location = 1;
|
|
slot = 0;
|
|
}
|
|
#endif // USE_UFILESYS
|
|
while (slot <= max_slots) { // Read all config pages in search of valid and latest
|
|
if (slot > 0) {
|
|
flash_location = (1 == slot) ? EEPROM_LOCATION : (2 == slot) ? SETTINGS_LOCATION : flash_location -1;
|
|
ESP.flashRead(flash_location * SPI_FLASH_SEC_SIZE, (uint32*)Settings, sizeof(TSettings));
|
|
}
|
|
if ((Settings->cfg_crc32 != 0xFFFFFFFF) && (Settings->cfg_crc32 != 0x00000000) && (Settings->cfg_crc32 == GetSettingsCrc32())) {
|
|
if (Settings->save_flag > save_flag) { // Find latest page based on incrementing save_flag
|
|
save_flag = Settings->save_flag;
|
|
settings_location = flash_location;
|
|
if (Settings->flag.stop_flash_rotate && (1 == slot)) { // Stop if only eeprom area should be used and it is valid
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
slot++;
|
|
delay(1);
|
|
}
|
|
if (settings_location > 0) {
|
|
#ifdef USE_UFILESYS
|
|
if (1 == settings_location) {
|
|
TfsLoadFile(TASM_FILE_SETTINGS, (uint8_t*)Settings, sizeof(TSettings));
|
|
AddLog(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from File, " D_COUNT " %lu"), Settings->save_flag);
|
|
} else
|
|
#endif // USE_UFILESYS
|
|
{
|
|
ESP.flashRead(settings_location * SPI_FLASH_SEC_SIZE, (uint32*)Settings, sizeof(TSettings));
|
|
AddLog(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_LOADED_FROM_FLASH_AT " %X, " D_COUNT " %lu"), settings_location, Settings->save_flag);
|
|
}
|
|
}
|
|
#endif // ESP8266
|
|
|
|
#ifdef ESP32
|
|
uint32_t source = SettingsRead(Settings, sizeof(TSettings));
|
|
if (source) {
|
|
settings_location = 1;
|
|
if (Settings->cfg_holder == (uint16_t)CFG_HOLDER) {
|
|
AddLog(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from %s, " D_COUNT " %lu"), (2 == source)?"File":"NVS", Settings->save_flag);
|
|
}
|
|
}
|
|
#endif // ESP32
|
|
|
|
#ifndef FIRMWARE_MINIMAL
|
|
if ((0 == settings_location) || (Settings->cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h
|
|
// if ((0 == settings_location) || (Settings->cfg_size != sizeof(TSettings)) || (Settings->cfg_holder != (uint16_t)CFG_HOLDER)) { // Init defaults if cfg_holder differs from user settings in my_user_config.h
|
|
#ifdef USE_UFILESYS
|
|
if (TfsLoadFile(TASM_FILE_SETTINGS_LKG, (uint8_t*)Settings, sizeof(TSettings)) && (Settings->cfg_crc32 == GetSettingsCrc32())) {
|
|
settings_location = 1;
|
|
AddLog(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG "Loaded from LKG File, " D_COUNT " %lu"), Settings->save_flag);
|
|
} else
|
|
#endif // USE_UFILESYS
|
|
{
|
|
SettingsDefault();
|
|
}
|
|
}
|
|
settings_crc32 = GetSettingsCrc32();
|
|
#endif // FIRMWARE_MINIMAL
|
|
|
|
RtcSettingsLoad(1);
|
|
}
|
|
|
|
// Used in TLS - returns the timestamp of the last Flash settings write
|
|
uint32_t CfgTime(void) {
|
|
return Settings->cfg_timestamp;
|
|
}
|
|
|
|
#ifdef ESP8266
|
|
void SettingsErase(uint8_t type) {
|
|
/*
|
|
For Arduino core and SDK:
|
|
Erase only works from flash start address to SDK recognized flash end address (flashchip->chip_size = ESP.getFlashChipSize).
|
|
Addresses above SDK recognized size (up to ESP.getFlashChipRealSize) are not accessable.
|
|
For Esptool:
|
|
The only way to erase whole flash is esptool which uses direct SPI writes to flash.
|
|
|
|
The default erase function is EspTool (EsptoolErase)
|
|
|
|
0 = Erase from program end until end of flash as seen by SDK including optional filesystem
|
|
1 = Erase 16k SDK parameter area near end of flash as seen by SDK (0x0XFCxxx - 0x0XFFFFF) solving possible wifi errors
|
|
2 = Erase from program end until end of flash as seen by SDK excluding optional filesystem
|
|
3 = Erase Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
|
4 = Erase SDK parameter area used for wifi calibration (0x0FCxxx - 0x0FCFFF)
|
|
*/
|
|
|
|
#ifndef FIRMWARE_MINIMAL
|
|
// Reset 2 = Erase all flash from program end to end of physical flash
|
|
uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1;
|
|
uint32_t _sectorEnd = ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE; // Flash size as reported by hardware
|
|
if (1 == type) { // Reset 3 = SDK parameter area
|
|
// source Esp.cpp and core_esp8266_phy.cpp
|
|
_sectorStart = (ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE) - 4;
|
|
}
|
|
else if (2 == type) { // Reset 5, 6 = Erase all flash from program end to end of physical flash but skip filesystem
|
|
/*
|
|
#ifdef USE_UFILESYS
|
|
TfsDeleteFile(TASM_FILE_SETTINGS); // Not needed as it is recreated by set defaults before restart
|
|
#endif
|
|
*/
|
|
EsptoolErase(_sectorStart, FLASH_FS_START);
|
|
_sectorStart = EEPROM_LOCATION;
|
|
_sectorEnd = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; // Flash size as seen by SDK
|
|
}
|
|
else if (3 == type) { // QPC Reached = QPC and Tasmota and SDK parameter area (0x0F3xxx - 0x0FFFFF)
|
|
#ifdef USE_UFILESYS
|
|
TfsDeleteFile(TASM_FILE_SETTINGS);
|
|
#endif
|
|
EsptoolErase(SETTINGS_LOCATION - CFG_ROTATES, SETTINGS_LOCATION +1);
|
|
_sectorStart = EEPROM_LOCATION;
|
|
_sectorEnd = ESP.getFlashChipSize() / SPI_FLASH_SEC_SIZE; // Flash size as seen by SDK
|
|
}
|
|
else if (4 == type) { // WIFI_FORCE_RF_CAL_ERASE = SDK wifi calibration
|
|
_sectorStart = EEPROM_LOCATION +1; // SDK phy area and Core calibration sector (0x0XFC000)
|
|
_sectorEnd = _sectorStart +1; // SDK end of phy area and Core calibration sector (0x0XFCFFF)
|
|
}
|
|
|
|
EsptoolErase(_sectorStart, _sectorEnd); // Esptool - erases flash completely
|
|
#endif // FIRMWARE_MINIMAL
|
|
}
|
|
#endif // ESP8266
|
|
|
|
void SettingsSdkErase(void) {
|
|
WiFi.disconnect(false); // Delete SDK wifi config
|
|
SettingsErase(1);
|
|
delay(1000);
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
void SettingsDefault(void) {
|
|
AddLog(LOG_LEVEL_NONE, PSTR(D_LOG_CONFIG D_USE_DEFAULTS));
|
|
SettingsDefaultSet1();
|
|
SettingsDefaultSet2();
|
|
SettingsDefaultSet3();
|
|
SettingsSave(2);
|
|
}
|
|
|
|
void SettingsDefaultSet1(void) {
|
|
memset(Settings, 0x00, sizeof(TSettings));
|
|
|
|
Settings->cfg_holder = (uint16_t)CFG_HOLDER;
|
|
Settings->cfg_size = sizeof(TSettings);
|
|
// Settings->save_flag = 0;
|
|
Settings->version = VERSION;
|
|
// Settings->bootcount = 0;
|
|
// Settings->cfg_crc = 0;
|
|
}
|
|
|
|
// default Fingerprints in PROGMEM
|
|
const uint8_t default_fingerprint1[] PROGMEM = { MQTT_FINGERPRINT1 };
|
|
const uint8_t default_fingerprint2[] PROGMEM = { MQTT_FINGERPRINT2 };
|
|
|
|
void SettingsDefaultSet2(void) {
|
|
memset((char*)Settings +16, 0x00, sizeof(TSettings) -16);
|
|
|
|
// this little trick allows GCC to optimize the assignment by grouping values and doing only ORs
|
|
SOBitfield flag = { 0 };
|
|
SOBitfield3 flag3 = { 0 };
|
|
SOBitfield4 flag4 = { 0 };
|
|
SOBitfield5 flag5 = { 0 };
|
|
SysMBitfield1 flag2 = { 0 };
|
|
SysMBitfield2 mbflag2 = { 0 };
|
|
|
|
#ifdef ESP8266
|
|
Settings->gpio16_converted = 0xF5A0;
|
|
// Settings->config_version = 0; // ESP8266 (Has been 0 for long time)
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
|
Settings->config_version = 2; // ESP32S3
|
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
Settings->config_version = 3; // ESP32S2
|
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
Settings->config_version = 4; // ESP32C3
|
|
#else
|
|
Settings->config_version = 1; // ESP32
|
|
#endif // CONFIG_IDF_TARGET_ESP32S3
|
|
#endif // ESP32
|
|
|
|
flag.stop_flash_rotate |= APP_FLASH_CYCLE;
|
|
flag.global_state |= APP_ENABLE_LEDLINK;
|
|
flag3.sleep_normal |= APP_NORMAL_SLEEP;
|
|
flag3.no_power_feedback |= APP_NO_RELAY_SCAN;
|
|
flag3.fast_power_cycle_disable |= APP_DISABLE_POWERCYCLE;
|
|
flag3.bootcount_update |= DEEPSLEEP_BOOTCOUNT;
|
|
flag3.mqtt_buttons |= MQTT_BUTTONS;
|
|
Settings->save_data = SAVE_DATA;
|
|
Settings->param[P_BACKLOG_DELAY] = MIN_BACKLOG_DELAY;
|
|
Settings->param[P_BOOT_LOOP_OFFSET] = BOOT_LOOP_OFFSET; // SetOption36
|
|
Settings->param[P_RGB_REMAP] = RGB_REMAP_RGBW;
|
|
Settings->sleep = APP_SLEEP;
|
|
if (Settings->sleep < 50) {
|
|
Settings->sleep = 50; // Default to 50 for sleep, for now
|
|
}
|
|
|
|
// Module
|
|
flag.interlock |= APP_INTERLOCK_MODE;
|
|
Settings->interlock[0] = APP_INTERLOCK_GROUP_1;
|
|
Settings->interlock[1] = APP_INTERLOCK_GROUP_2;
|
|
Settings->interlock[2] = APP_INTERLOCK_GROUP_3;
|
|
Settings->interlock[3] = APP_INTERLOCK_GROUP_4;
|
|
Settings->module = MODULE;
|
|
Settings->fallback_module = FALLBACK_MODULE;
|
|
ModuleDefault(WEMOS);
|
|
// for (uint32_t i = 0; i < nitems(Settings->my_gp.io); i++) { Settings->my_gp.io[i] = GPIO_NONE; }
|
|
SettingsUpdateText(SET_FRIENDLYNAME1, PSTR(FRIENDLY_NAME));
|
|
SettingsUpdateText(SET_FRIENDLYNAME2, PSTR(FRIENDLY_NAME"2"));
|
|
SettingsUpdateText(SET_FRIENDLYNAME3, PSTR(FRIENDLY_NAME"3"));
|
|
SettingsUpdateText(SET_FRIENDLYNAME4, PSTR(FRIENDLY_NAME"4"));
|
|
#ifdef DEVICE_NAME
|
|
SettingsUpdateText(SET_DEVICENAME, PSTR(DEVICE_NAME));
|
|
#else
|
|
SettingsUpdateText(SET_DEVICENAME, SettingsText(SET_FRIENDLYNAME1));
|
|
#endif
|
|
SettingsUpdateText(SET_OTAURL, PSTR(OTA_URL));
|
|
|
|
// Power
|
|
flag.save_state |= SAVE_STATE;
|
|
Settings->power = APP_POWER;
|
|
Settings->poweronstate = APP_POWERON_STATE;
|
|
Settings->blinktime = APP_BLINKTIME;
|
|
Settings->blinkcount = APP_BLINKCOUNT;
|
|
Settings->ledstate = APP_LEDSTATE;
|
|
Settings->ledmask = APP_LEDMASK;
|
|
// Settings->ledpwm_off = 0;
|
|
Settings->ledpwm_on = 255;
|
|
// Settings->ledpwm_mask = 0;
|
|
Settings->pulse_timer[0] = APP_PULSETIME;
|
|
// for (uint32_t i = 1; i < MAX_PULSETIMERS; i++) { Settings->pulse_timer[i] = 0; }
|
|
|
|
// Serial
|
|
Settings->serial_config = TS_SERIAL_8N1;
|
|
Settings->baudrate = APP_BAUDRATE / 300;
|
|
Settings->sbaudrate = SOFT_BAUDRATE / 300;
|
|
Settings->serial_delimiter = 0xff;
|
|
Settings->seriallog_level = SERIAL_LOG_LEVEL;
|
|
|
|
// Ethernet
|
|
flag4.network_ethernet |= 1;
|
|
#ifdef ESP32
|
|
Settings->eth_type = ETH_TYPE;
|
|
Settings->eth_clk_mode = ETH_CLKMODE;
|
|
Settings->eth_address = ETH_ADDRESS;
|
|
#endif // ESP32
|
|
|
|
// Wifi
|
|
flag4.network_wifi |= 1;
|
|
flag3.use_wifi_scan |= WIFI_SCAN_AT_RESTART;
|
|
flag3.use_wifi_rescan |= WIFI_SCAN_REGULARLY;
|
|
Settings->wifi_output_power = 170;
|
|
Settings->param[P_ARP_GRATUITOUS] = WIFI_ARP_INTERVAL;
|
|
ParseIPv4(&Settings->ipv4_address[0], PSTR(WIFI_IP_ADDRESS));
|
|
ParseIPv4(&Settings->ipv4_address[1], PSTR(WIFI_GATEWAY));
|
|
ParseIPv4(&Settings->ipv4_address[2], PSTR(WIFI_SUBNETMASK));
|
|
ParseIPv4(&Settings->ipv4_address[3], PSTR(WIFI_DNS));
|
|
ParseIPv4(&Settings->ipv4_address[4], PSTR(WIFI_DNS2));
|
|
ParseIPv4(&Settings->ipv4_rgx_address, PSTR(WIFI_RGX_IP_ADDRESS));
|
|
ParseIPv4(&Settings->ipv4_rgx_subnetmask, PSTR(WIFI_RGX_SUBNETMASK));
|
|
Settings->sta_config = WIFI_CONFIG_TOOL;
|
|
// Settings->sta_active = 0;
|
|
SettingsUpdateText(SET_STASSID1, PSTR(STA_SSID1));
|
|
SettingsUpdateText(SET_STASSID2, PSTR(STA_SSID2));
|
|
SettingsUpdateText(SET_STAPWD1, PSTR(STA_PASS1));
|
|
SettingsUpdateText(SET_STAPWD2, PSTR(STA_PASS2));
|
|
SettingsUpdateText(SET_HOSTNAME, WIFI_HOSTNAME);
|
|
SettingsUpdateText(SET_RGX_SSID, PSTR(WIFI_RGX_SSID));
|
|
SettingsUpdateText(SET_RGX_PASSWORD, PSTR(WIFI_RGX_PASSWORD));
|
|
Settings->sbflag1.range_extender = WIFI_RGX_STATE;
|
|
Settings->sbflag1.range_extender_napt = WIFI_RGX_NAPT;
|
|
|
|
// Syslog
|
|
SettingsUpdateText(SET_SYSLOG_HOST, PSTR(SYS_LOG_HOST));
|
|
Settings->syslog_port = SYS_LOG_PORT;
|
|
Settings->syslog_level = SYS_LOG_LEVEL;
|
|
|
|
// Webserver
|
|
flag2.emulation |= EMULATION;
|
|
flag4.alexa_gen_1 |= EMULATION_HUE_1ST_GEN;
|
|
flag3.gui_hostname_ip |= GUI_SHOW_HOSTNAME;
|
|
flag3.mdns_enabled |= MDNS_ENABLED;
|
|
Settings->webserver = WEB_SERVER;
|
|
Settings->weblog_level = WEB_LOG_LEVEL;
|
|
SettingsUpdateText(SET_WEBPWD, PSTR(WEB_PASSWORD));
|
|
SettingsUpdateText(SET_CORS, PSTR(CORS_DOMAIN));
|
|
#ifdef DISABLE_REFERER_CHK
|
|
flag5.disable_referer_chk |= false;
|
|
#else
|
|
flag5.disable_referer_chk |= true;
|
|
#endif
|
|
// Button
|
|
flag.button_restrict |= KEY_DISABLE_MULTIPRESS;
|
|
flag.button_swap |= KEY_SWAP_DOUBLE_PRESS;
|
|
flag.button_single |= KEY_ONLY_SINGLE_PRESS;
|
|
Settings->param[P_HOLD_TIME] = KEY_HOLD_TIME; // Default 4 seconds hold time
|
|
|
|
// Switch
|
|
for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) { Settings->switchmode[i] = SWITCH_MODE; }
|
|
|
|
// MQTT
|
|
flag.mqtt_enabled |= MQTT_USE;
|
|
flag.mqtt_response |= MQTT_RESULT_COMMAND;
|
|
flag.mqtt_offline |= MQTT_LWT_MESSAGE;
|
|
flag.mqtt_power_retain |= MQTT_POWER_RETAIN;
|
|
flag.mqtt_button_retain |= MQTT_BUTTON_RETAIN;
|
|
flag.mqtt_switch_retain |= MQTT_SWITCH_RETAIN;
|
|
flag.mqtt_sensor_retain |= MQTT_SENSOR_RETAIN;
|
|
flag5.mqtt_info_retain |= MQTT_INFO_RETAIN;
|
|
flag5.mqtt_state_retain |= MQTT_STATE_RETAIN;
|
|
flag5.mqtt_switches |= MQTT_SWITCHES;
|
|
// flag.mqtt_serial |= 0;
|
|
flag.device_index_enable |= MQTT_POWER_FORMAT;
|
|
flag3.time_append_timezone |= MQTT_APPEND_TIMEZONE;
|
|
flag3.button_switch_force_local |= MQTT_BUTTON_SWITCH_FORCE_LOCAL;
|
|
flag3.no_hold_retain |= MQTT_NO_HOLD_RETAIN;
|
|
flag3.use_underscore |= MQTT_INDEX_SEPARATOR;
|
|
flag3.grouptopic_mode |= MQTT_GROUPTOPIC_FORMAT;
|
|
SettingsUpdateText(SET_MQTT_HOST, MQTT_HOST);
|
|
Settings->mqtt_port = MQTT_PORT;
|
|
SettingsUpdateText(SET_MQTT_CLIENT, PSTR(MQTT_CLIENT_ID));
|
|
SettingsUpdateText(SET_MQTT_USER, PSTR(MQTT_USER));
|
|
SettingsUpdateText(SET_MQTT_PWD, PSTR(MQTT_PASS));
|
|
SettingsUpdateText(SET_MQTT_TOPIC, PSTR(MQTT_TOPIC));
|
|
SettingsUpdateText(SET_MQTT_BUTTON_TOPIC, PSTR(MQTT_BUTTON_TOPIC));
|
|
SettingsUpdateText(SET_MQTT_SWITCH_TOPIC, PSTR(MQTT_SWITCH_TOPIC));
|
|
SettingsUpdateText(SET_MQTT_GRP_TOPIC, PSTR(MQTT_GRPTOPIC));
|
|
SettingsUpdateText(SET_MQTT_FULLTOPIC, PSTR(MQTT_FULLTOPIC));
|
|
Settings->mqtt_retry = MQTT_RETRY_SECS;
|
|
SettingsUpdateText(SET_MQTTPREFIX1, PSTR(SUB_PREFIX));
|
|
SettingsUpdateText(SET_MQTTPREFIX2, PSTR(PUB_PREFIX));
|
|
SettingsUpdateText(SET_MQTTPREFIX3, PSTR(PUB_PREFIX2));
|
|
SettingsUpdateText(SET_STATE_TXT1, PSTR(MQTT_STATUS_OFF));
|
|
SettingsUpdateText(SET_STATE_TXT2, PSTR(MQTT_STATUS_ON));
|
|
SettingsUpdateText(SET_STATE_TXT3, PSTR(MQTT_CMND_TOGGLE));
|
|
SettingsUpdateText(SET_STATE_TXT4, PSTR(MQTT_CMND_HOLD));
|
|
memcpy_P(Settings->mqtt_fingerprint[0], default_fingerprint1, sizeof(default_fingerprint1));
|
|
memcpy_P(Settings->mqtt_fingerprint[1], default_fingerprint2, sizeof(default_fingerprint2));
|
|
Settings->tele_period = TELE_PERIOD;
|
|
Settings->mqttlog_level = MQTT_LOG_LEVEL;
|
|
Settings->mqtt_keepalive = MQTT_KEEPALIVE;
|
|
Settings->mqtt_socket_timeout = MQTT_SOCKET_TIMEOUT;
|
|
Settings->mqtt_wifi_timeout = MQTT_WIFI_CLIENT_TIMEOUT / 100;
|
|
|
|
// Energy
|
|
flag.no_power_on_check |= ENERGY_VOLTAGE_ALWAYS;
|
|
flag2.current_resolution |= 3;
|
|
// flag2.voltage_resolution |= 0;
|
|
// flag2.wattage_resolution |= 0;
|
|
flag2.energy_resolution |= ENERGY_RESOLUTION;
|
|
flag3.dds2382_model |= ENERGY_DDS2382_MODE;
|
|
flag3.hardware_energy_total |= ENERGY_HARDWARE_TOTALS;
|
|
Settings->param[P_MAX_POWER_RETRY] = MAX_POWER_RETRY;
|
|
// Settings->energy_power_delta[0] = 0;
|
|
// Settings->energy_power_delta[1] = 0;
|
|
// Settings->energy_power_delta[2] = 0;
|
|
Settings->energy_power_calibration = HLW_PREF_PULSE;
|
|
Settings->energy_voltage_calibration = HLW_UREF_PULSE;
|
|
Settings->energy_current_calibration = HLW_IREF_PULSE;
|
|
// Settings->energy_kWhtoday = 0;
|
|
// Settings->energy_kWhyesterday = 0;
|
|
// Settings->energy_kWhdoy = 0;
|
|
// Settings->energy_min_power = 0;
|
|
// Settings->energy_max_power = 0;
|
|
// Settings->energy_min_voltage = 0;
|
|
// Settings->energy_max_voltage = 0;
|
|
// Settings->energy_min_current = 0;
|
|
// Settings->energy_max_current = 0;
|
|
// Settings->energy_max_power_limit = 0; // MaxPowerLimit
|
|
Settings->energy_max_power_limit_hold = MAX_POWER_HOLD;
|
|
Settings->energy_max_power_limit_window = MAX_POWER_WINDOW;
|
|
// Settings->energy_max_power_safe_limit = 0; // MaxSafePowerLimit
|
|
Settings->energy_max_power_safe_limit_hold = SAFE_POWER_HOLD;
|
|
Settings->energy_max_power_safe_limit_window = SAFE_POWER_WINDOW;
|
|
// Settings->energy_max_energy = 0; // MaxEnergy
|
|
// Settings->energy_max_energy_start = 0; // MaxEnergyStart
|
|
// Settings->energy_kWhtotal = 0;
|
|
RtcSettings.energy_kWhtotal = 0;
|
|
// memset((char*)&Settings->energy_usage, 0x00, sizeof(Settings->energy_usage));
|
|
memset((char*)&RtcSettings.energy_usage, 0x00, sizeof(RtcSettings.energy_usage));
|
|
Settings->param[P_OVER_TEMP] = ENERGY_OVERTEMP;
|
|
|
|
// IRRemote
|
|
flag.ir_receive_decimal |= IR_DATA_RADIX;
|
|
flag3.receive_raw |= IR_ADD_RAW_DATA;
|
|
Settings->param[P_IR_UNKNOW_THRESHOLD] = IR_RCV_MIN_UNKNOWN_SIZE;
|
|
Settings->param[P_IR_TOLERANCE] = IR_RCV_TOLERANCE;
|
|
|
|
// RF Bridge
|
|
flag.rf_receive_decimal |= RF_DATA_RADIX;
|
|
// for (uint32_t i = 0; i < 17; i++) { Settings->rf_code[i][0] = 0; }
|
|
memcpy_P(Settings->rf_code[0], kDefaultRfCode, 9);
|
|
|
|
// Domoticz
|
|
Settings->domoticz_update_timer = DOMOTICZ_UPDATE_TIMER;
|
|
// for (uint32_t i = 0; i < MAX_DOMOTICZ_IDX; i++) {
|
|
// Settings->domoticz_relay_idx[i] = 0;
|
|
// Settings->domoticz_key_idx[i] = 0;
|
|
// Settings->domoticz_switch_idx[i] = 0;
|
|
// }
|
|
// for (uint32_t i = 0; i < MAX_DOMOTICZ_SNS_IDX; i++) {
|
|
// Settings->domoticz_sensor_idx[i] = 0;
|
|
// }
|
|
|
|
// Sensor
|
|
flag.temperature_conversion |= TEMP_CONVERSION;
|
|
flag.pressure_conversion |= PRESSURE_CONVERSION;
|
|
flag2.pressure_resolution |= PRESSURE_RESOLUTION;
|
|
flag2.humidity_resolution |= HUMIDITY_RESOLUTION;
|
|
flag2.temperature_resolution |= TEMP_RESOLUTION;
|
|
flag3.ds18x20_internal_pullup |= DS18X20_PULL_UP;
|
|
flag3.counter_reset_on_tele |= COUNTER_RESET;
|
|
// Settings->altitude = 0;
|
|
|
|
// Rules
|
|
// Settings->rule_enabled = 0;
|
|
// Settings->rule_once = 0;
|
|
// for (uint32_t i = 1; i < MAX_RULE_SETS; i++) { Settings->rules[i][0] = '\0'; }
|
|
flag2.calc_resolution |= CALC_RESOLUTION;
|
|
|
|
// Timer
|
|
flag3.timers_enable |= TIMERS_ENABLED;
|
|
|
|
// Home Assistant
|
|
flag.hass_light |= HASS_AS_LIGHT;
|
|
flag.hass_discovery |= HOME_ASSISTANT_DISCOVERY_ENABLE;
|
|
flag3.hass_tele_on_power |= TELE_ON_POWER;
|
|
|
|
// Knx
|
|
flag.knx_enabled |= KNX_ENABLED;
|
|
flag.knx_enable_enhancement |= KNX_ENHANCED;
|
|
|
|
// Light
|
|
flag.pwm_control |= LIGHT_MODE;
|
|
flag.ws_clock_reverse |= LIGHT_CLOCK_DIRECTION;
|
|
flag.light_signal |= LIGHT_PAIRS_CO2;
|
|
flag.not_power_linked |= LIGHT_POWER_CONTROL;
|
|
flag.decimal_text |= LIGHT_COLOR_RADIX;
|
|
flag3.pwm_multi_channels |= LIGHT_CHANNEL_MODE;
|
|
flag3.slider_dimmer_stay_on |= LIGHT_SLIDER_POWER;
|
|
flag4.alexa_ct_range |= LIGHT_ALEXA_CT_RANGE;
|
|
flag4.pwm_ct_mode |= LIGHT_PWM_CT_MODE;
|
|
flag4.white_blend_mode |= LIGHT_WHITE_BLEND_MODE;
|
|
flag4.virtual_ct |= LIGHT_VIRTUAL_CT;
|
|
flag4.virtual_ct_cw |= LIGHT_VIRTUAL_CT_CW;
|
|
|
|
Settings->pwm_frequency = PWM_FREQ;
|
|
Settings->pwm_range = PWM_RANGE;
|
|
for (uint32_t i = 0; i < LST_MAX; i++) {
|
|
Settings->light_color[i] = DEFAULT_LIGHT_COMPONENT;
|
|
// Settings->pwm_value[i] = 0;
|
|
}
|
|
Settings->light_correction = 1;
|
|
Settings->light_dimmer = DEFAULT_LIGHT_DIMMER;
|
|
// Settings->light_fade = 0;
|
|
Settings->light_speed = 1;
|
|
// Settings->light_scheme = 0;
|
|
Settings->light_width = 1;
|
|
// Settings->light_wakeup = 0;
|
|
Settings->light_pixels = WS2812_LEDS;
|
|
// Settings->light_rotation = 0;
|
|
Settings->ws_width[WS_SECOND] = 1;
|
|
Settings->ws_color[WS_SECOND][WS_RED] = 255;
|
|
// Settings->ws_color[WS_SECOND][WS_GREEN] = 0;
|
|
Settings->ws_color[WS_SECOND][WS_BLUE] = 255;
|
|
Settings->ws_width[WS_MINUTE] = 3;
|
|
// Settings->ws_color[WS_MINUTE][WS_RED] = 0;
|
|
Settings->ws_color[WS_MINUTE][WS_GREEN] = 255;
|
|
// Settings->ws_color[WS_MINUTE][WS_BLUE] = 0;
|
|
Settings->ws_width[WS_HOUR] = 5;
|
|
Settings->ws_color[WS_HOUR][WS_RED] = 255;
|
|
// Settings->ws_color[WS_HOUR][WS_GREEN] = 0;
|
|
// Settings->ws_color[WS_HOUR][WS_BLUE] = 0;
|
|
|
|
Settings->dimmer_hw_max = DEFAULT_DIMMER_MAX;
|
|
Settings->dimmer_hw_min = DEFAULT_DIMMER_MIN;
|
|
|
|
Settings->dimmer_step = DEFAULT_DIMMER_STEP;
|
|
|
|
// Device Groups
|
|
*(uint32_t *)&Settings->device_group_tie = 0x04030201;
|
|
|
|
// Display
|
|
// Settings->display_model = 0;
|
|
Settings->display_mode = 1;
|
|
Settings->display_refresh = 2;
|
|
Settings->display_rows = 2;
|
|
Settings->display_cols[0] = 16;
|
|
Settings->display_cols[1] = 8;
|
|
Settings->display_dimmer_protected = -10; // 10%
|
|
Settings->display_size = 1;
|
|
Settings->display_font = 1;
|
|
// Settings->display_rotate = 0;
|
|
Settings->display_address[0] = MTX_ADDRESS1;
|
|
Settings->display_address[1] = MTX_ADDRESS2;
|
|
Settings->display_address[2] = MTX_ADDRESS3;
|
|
Settings->display_address[3] = MTX_ADDRESS4;
|
|
Settings->display_address[4] = MTX_ADDRESS5;
|
|
Settings->display_address[5] = MTX_ADDRESS6;
|
|
Settings->display_address[6] = MTX_ADDRESS7;
|
|
Settings->display_address[7] = MTX_ADDRESS8;
|
|
|
|
// Time
|
|
if (((APP_TIMEZONE > -14) && (APP_TIMEZONE < 15)) || (99 == APP_TIMEZONE)) {
|
|
Settings->timezone = APP_TIMEZONE;
|
|
Settings->timezone_minutes = 0;
|
|
} else {
|
|
Settings->timezone = APP_TIMEZONE / 60;
|
|
Settings->timezone_minutes = abs(APP_TIMEZONE % 60);
|
|
}
|
|
SettingsUpdateText(SET_NTPSERVER1, PSTR(NTP_SERVER1));
|
|
SettingsUpdateText(SET_NTPSERVER2, PSTR(NTP_SERVER2));
|
|
SettingsUpdateText(SET_NTPSERVER3, PSTR(NTP_SERVER3));
|
|
for (uint32_t i = 0; i < MAX_NTP_SERVERS; i++) {
|
|
SettingsUpdateText(SET_NTPSERVER1 +i, ReplaceCommaWithDot(SettingsText(SET_NTPSERVER1 +i)));
|
|
}
|
|
Settings->latitude = (int)((double)LATITUDE * 1000000);
|
|
Settings->longitude = (int)((double)LONGITUDE * 1000000);
|
|
SettingsResetStd();
|
|
SettingsResetDst();
|
|
|
|
Settings->button_debounce = KEY_DEBOUNCE_TIME;
|
|
Settings->switch_debounce = SWITCH_DEBOUNCE_TIME;
|
|
|
|
for (uint32_t j = 0; j < 5; j++) {
|
|
Settings->rgbwwTable[j] = 255;
|
|
}
|
|
|
|
Settings->novasds_startingoffset = STARTING_OFFSET;
|
|
|
|
SettingsDefaultWebColor();
|
|
|
|
memset(&Settings->sensors, 0xFF, 32); // Enable all possible sensors
|
|
SettingsEnableAllI2cDrivers();
|
|
|
|
// Tuya
|
|
flag3.tuya_apply_o20 |= TUYA_SETOPTION_20;
|
|
flag5.tuya_allow_dimmer_0 |= TUYA_ALLOW_DIMMER_0;
|
|
flag3.tuya_serial_mqtt_publish |= MQTT_TUYA_RECEIVED;
|
|
mbflag2.temperature_set_res |= TUYA_TEMP_SET_RES;
|
|
|
|
flag3.buzzer_enable |= BUZZER_ENABLE;
|
|
flag3.shutter_mode |= SHUTTER_SUPPORT;
|
|
flag3.pcf8574_ports_inverted |= PCF8574_INVERT_PORTS;
|
|
flag4.zigbee_use_names |= ZIGBEE_FRIENDLY_NAMES;
|
|
flag4.zigbee_distinct_topics |= ZIGBEE_DISTINCT_TOPICS;
|
|
flag4.remove_zbreceived |= ZIGBEE_RMV_ZBRECEIVED;
|
|
flag4.zb_index_ep |= ZIGBEE_INDEX_EP;
|
|
flag4.mqtt_tls |= MQTT_TLS_ENABLED;
|
|
flag4.mqtt_no_retain |= MQTT_NO_RETAIN;
|
|
|
|
flag5.shift595_invert_outputs |= SHIFT595_INVERT_OUTPUTS;
|
|
Settings->shift595_device_count = SHIFT595_DEVICE_COUNT;
|
|
flag5.tls_use_fingerprint |= MQTT_TLS_FINGERPRINT;
|
|
|
|
Settings->flag = flag;
|
|
Settings->flag2 = flag2;
|
|
Settings->flag3 = flag3;
|
|
Settings->flag4 = flag4;
|
|
Settings->flag5 = flag5;
|
|
}
|
|
|
|
void SettingsDefaultSet3(void) {
|
|
#ifdef USER_TEMPLATE
|
|
String user_template = USER_TEMPLATE;
|
|
JsonTemplate((char*)user_template.c_str());
|
|
user_template = (const char*) nullptr; // Force deallocation of the String internal memory
|
|
#endif
|
|
|
|
#ifdef USE_RULES
|
|
#ifdef USER_RULE1
|
|
String user_rule1 = F("Rule1 ");
|
|
user_rule1 += USER_RULE1;
|
|
ExecuteCommand((char*)user_rule1.c_str(), SRC_RESTART);
|
|
user_rule1 = (const char*) nullptr; // Force deallocation of the String internal memory
|
|
#endif
|
|
|
|
#ifdef USER_RULE2
|
|
String user_rule2 = F("Rule2 ");
|
|
user_rule2 += USER_RULE2;
|
|
ExecuteCommand((char*)user_rule2.c_str(), SRC_RESTART);
|
|
user_rule2 = (const char*) nullptr; // Force deallocation of the String internal memory
|
|
#endif
|
|
|
|
#ifdef USER_RULE3
|
|
String user_rule3 = F("Rule3 ");
|
|
user_rule3 += USER_RULE3;
|
|
ExecuteCommand((char*)user_rule3.c_str(), SRC_RESTART);
|
|
user_rule3 = (const char*) nullptr; // Force deallocation of the String internal memory
|
|
#endif
|
|
#endif // USE_RULES
|
|
|
|
#ifdef USER_BACKLOG
|
|
String user_backlog = F("Backlog0 ");
|
|
user_backlog += USER_BACKLOG;
|
|
ExecuteCommand((char*)user_backlog.c_str(), SRC_RESTART);
|
|
user_backlog = (const char*) nullptr; // Force deallocation of the String internal memory
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
void SettingsResetStd(void) {
|
|
Settings->tflag[0].hemis = TIME_STD_HEMISPHERE;
|
|
Settings->tflag[0].week = TIME_STD_WEEK;
|
|
Settings->tflag[0].dow = TIME_STD_DAY;
|
|
Settings->tflag[0].month = TIME_STD_MONTH;
|
|
Settings->tflag[0].hour = TIME_STD_HOUR;
|
|
Settings->toffset[0] = TIME_STD_OFFSET;
|
|
}
|
|
|
|
void SettingsResetDst(void) {
|
|
Settings->tflag[1].hemis = TIME_DST_HEMISPHERE;
|
|
Settings->tflag[1].week = TIME_DST_WEEK;
|
|
Settings->tflag[1].dow = TIME_DST_DAY;
|
|
Settings->tflag[1].month = TIME_DST_MONTH;
|
|
Settings->tflag[1].hour = TIME_DST_HOUR;
|
|
Settings->toffset[1] = TIME_DST_OFFSET;
|
|
}
|
|
|
|
void SettingsDefaultWebColor(void) {
|
|
char scolor[10];
|
|
for (uint32_t i = 0; i < COL_LAST; i++) {
|
|
WebHexCode(i, GetTextIndexed(scolor, sizeof(scolor), i, kWebColors));
|
|
}
|
|
}
|
|
|
|
void SettingsEnableAllI2cDrivers(void) {
|
|
Settings->i2c_drivers[0] = I2CDRIVERS_0_31;
|
|
Settings->i2c_drivers[1] = I2CDRIVERS_32_63;
|
|
Settings->i2c_drivers[2] = I2CDRIVERS_64_95;
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
void SettingsDelta(void) {
|
|
if (Settings->version != VERSION) { // Fix version dependent changes
|
|
|
|
#ifdef ESP8266
|
|
#ifndef UPGRADE_V8_MIN
|
|
// Although no direct upgrade is supported try to make a viable environment
|
|
if (Settings->version < 0x08000000) {
|
|
// Save SSIDs and Passwords
|
|
char temp31[strlen(Settings->ex_sta_ssid[0]) +1];
|
|
strncpy(temp31, Settings->ex_sta_ssid[0], sizeof(temp31));
|
|
char temp32[strlen(Settings->ex_sta_ssid[1]) +1];
|
|
strncpy(temp32, Settings->ex_sta_ssid[1], sizeof(temp32));
|
|
char temp41[strlen(Settings->ex_sta_pwd[0]) +1];
|
|
strncpy(temp41, Settings->ex_sta_pwd[0], sizeof(temp41));
|
|
char temp42[strlen(Settings->ex_sta_pwd[1]) +1];
|
|
strncpy(temp42, Settings->ex_sta_pwd[1], sizeof(temp42));
|
|
|
|
char temp7[strlen(Settings->ex_mqtt_host) +1];
|
|
strncpy(temp7, Settings->ex_mqtt_host, sizeof(temp7));
|
|
char temp9[strlen(Settings->ex_mqtt_user) +1];
|
|
strncpy(temp9, Settings->ex_mqtt_user, sizeof(temp9));
|
|
char temp10[strlen(Settings->ex_mqtt_pwd) +1];
|
|
strncpy(temp10, Settings->ex_mqtt_pwd, sizeof(temp10));
|
|
char temp11[strlen(Settings->ex_mqtt_topic) +1];
|
|
strncpy(temp11, Settings->ex_mqtt_topic, sizeof(temp11));
|
|
|
|
SettingsDefault();
|
|
|
|
// Restore current SSIDs and Passwords
|
|
SettingsUpdateText(SET_STASSID1, temp31);
|
|
SettingsUpdateText(SET_STASSID2, temp32);
|
|
SettingsUpdateText(SET_STAPWD1, temp41);
|
|
SettingsUpdateText(SET_STAPWD2, temp42);
|
|
|
|
#if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT)
|
|
if (!strlen(Settings->ex_mqtt_user)) {
|
|
SettingsUpdateText(SET_MQTT_HOST, temp7);
|
|
SettingsUpdateText(SET_MQTT_USER, temp9);
|
|
} else {
|
|
char aws_mqtt_host[66];
|
|
snprintf_P(aws_mqtt_host, sizeof(aws_mqtt_host), PSTR("%s%s"), temp9, temp7);
|
|
SettingsUpdateText(SET_MQTT_HOST, aws_mqtt_host);
|
|
SettingsUpdateText(SET_MQTT_USER, "");
|
|
}
|
|
#else // No USE_MQTT_TLS and USE_MQTT_AWS_IOT
|
|
SettingsUpdateText(SET_MQTT_HOST, temp7);
|
|
SettingsUpdateText(SET_MQTT_USER, temp9);
|
|
#endif // USE_MQTT_TLS and USE_MQTT_AWS_IOT
|
|
SettingsUpdateText(SET_MQTT_PWD, temp10);
|
|
SettingsUpdateText(SET_MQTT_TOPIC, temp11);
|
|
}
|
|
#endif // UPGRADE_V8_MIN
|
|
|
|
if (Settings->version < 0x08020003) {
|
|
SettingsUpdateText(SET_TEMPLATE_NAME, Settings->user_template_name);
|
|
Settings->zb_channel = 0; // set channel to zero to force reinit of zigbee parameters
|
|
}
|
|
#endif // ESP8266
|
|
|
|
if (Settings->version < 0x08020004) {
|
|
Settings->flag3.mqtt_buttons = 0; // SetOption73 (0) - Decouple button from relay and send just mqtt topic
|
|
#ifdef ESP8266
|
|
Settings->config_version = 0; // ESP8266 (Has been 0 for long time)
|
|
#endif // ESP8266
|
|
#ifdef ESP32
|
|
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
|
Settings->config_version = 2; // ESP32S3
|
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
Settings->config_version = 3; // ESP32S2
|
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
Settings->config_version = 4; // ESP32C3
|
|
#else
|
|
Settings->config_version = 1; // ESP32
|
|
#endif // CONFIG_IDF_TARGET_ESP32S3
|
|
#endif // ESP32
|
|
}
|
|
if (Settings->version < 0x08020006) {
|
|
#ifdef ESP32
|
|
Settings->module = WEMOS;
|
|
ModuleDefault(WEMOS);
|
|
#endif // ESP32
|
|
// make sure the empty rules have two consecutive NULLs, to be compatible with compressed rules
|
|
if (Settings->rules[0][0] == 0) { Settings->rules[0][1] = 0; }
|
|
if (Settings->rules[1][0] == 0) { Settings->rules[1][1] = 0; }
|
|
if (Settings->rules[2][0] == 0) { Settings->rules[2][1] = 0; }
|
|
}
|
|
if (Settings->version < 0x08030002) {
|
|
SettingsUpdateText(SET_DEVICENAME, SettingsText(SET_FRIENDLYNAME1));
|
|
Settings->ledpwm_off = 0;
|
|
Settings->ledpwm_on = 255;
|
|
Settings->ledpwm_mask = 0;
|
|
}
|
|
if (Settings->version < 0x08030104) {
|
|
Settings->flag4.network_wifi = 1;
|
|
Settings->flag4.network_ethernet = 1;
|
|
}
|
|
#ifdef ESP32
|
|
if (Settings->version < 0x08030105) {
|
|
Settings->eth_type = ETH_TYPE;
|
|
Settings->eth_clk_mode = ETH_CLKMODE;
|
|
Settings->eth_address = ETH_ADDRESS;
|
|
}
|
|
#endif // ESP32
|
|
if (Settings->version < 0x08030106) {
|
|
Settings->fallback_module = FALLBACK_MODULE;
|
|
}
|
|
if (Settings->version < 0x08040003) {
|
|
Settings->energy_power_delta[0] = Settings->hass_new_discovery; // replaced ex2_energy_power_delta on 8.5.0.1
|
|
Settings->energy_power_delta[1] = 0;
|
|
Settings->energy_power_delta[2] = 0;
|
|
}
|
|
#ifdef ESP8266
|
|
if (Settings->version < 0x09000002) {
|
|
char parameters[32];
|
|
snprintf_P(parameters, sizeof(parameters), PSTR("%d,%d,%d,%d,%d"),
|
|
Settings->influxdb_version, Settings->sensors[0][0], Settings->sensors[0][1], (int)Settings->sensors[0][2], Settings->mbflag2.data);
|
|
SettingsUpdateText(SET_ADC_PARAM1, parameters);
|
|
}
|
|
#endif // ESP8266
|
|
if (Settings->version < 0x09010000) {
|
|
Settings->dimmer_step = DEFAULT_DIMMER_STEP;
|
|
}
|
|
if (Settings->version < 0x09020003) {
|
|
Settings->flag3.use_wifi_rescan = true; // As a result of #10395
|
|
}
|
|
if (Settings->version < 0x09020006) {
|
|
for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) {
|
|
Settings->switchmode[i] = (i < 8) ? Settings->ex_switchmode[i] : SWITCH_MODE;
|
|
}
|
|
for (uint32_t i = 0; i < MAX_INTERLOCKS_SET; i++) {
|
|
Settings->interlock[i] = (i < 4) ? Settings->ex_interlock[i] : 0;
|
|
}
|
|
}
|
|
if (Settings->version < 0x09020007) {
|
|
*(uint32_t *)&Settings->device_group_tie = 0x04030201;
|
|
}
|
|
if (Settings->version < 0x09030102) {
|
|
Settings->mqtt_keepalive = MQTT_KEEPALIVE;
|
|
Settings->mqtt_socket_timeout = MQTT_SOCKET_TIMEOUT;
|
|
}
|
|
if (Settings->version < 0x09030104) {
|
|
Settings->mbflag2.data = 0;
|
|
}
|
|
if (Settings->version < 0x09040002) {
|
|
Settings->sbflag1.data = 0;
|
|
}
|
|
if (Settings->version < 0x09040006) {
|
|
Settings->mqtt_wifi_timeout = MQTT_WIFI_CLIENT_TIMEOUT / 100;
|
|
}
|
|
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
|
if (Settings->version < 0x09050002) {
|
|
if (Settings->cfg_size != sizeof(TSettings)) {
|
|
// Fix onetime Settings layout due to changed ESP32-C3 myio and mytmplt types sizes
|
|
memmove_P((uint8_t*)&Settings->user_template, (uint8_t*)&Settings->free_esp32c3_3D8, sizeof(TSettings) - 0x3FC);
|
|
memmove_P((uint8_t*)&Settings->eth_type, (uint8_t*)&Settings->free_esp32c3_42A, sizeof(TSettings) - 0x446);
|
|
// Reset for future use
|
|
memset(&Settings->free_esp32c3_3D8, 0x00, sizeof(Settings->free_esp32c3_3D8));
|
|
memset(&Settings->free_esp32c3_42A, 0x00, sizeof(Settings->free_esp32c3_42A));
|
|
}
|
|
}
|
|
#endif
|
|
if (Settings->version < 0x09050003) {
|
|
memset(&Settings->sensors, 0xFF, 16); // Enable all possible sensors
|
|
}
|
|
if (Settings->version < 0x09050004) {
|
|
Settings->energy_kWhtotal = Settings->ipv4_address[4];
|
|
ParseIPv4(&Settings->ipv4_address[4], PSTR(WIFI_DNS2));
|
|
}
|
|
if (Settings->version < 0x09050005) {
|
|
Settings->sbflag1.range_extender = WIFI_RGX_STATE;
|
|
Settings->sbflag1.range_extender_napt = WIFI_RGX_NAPT;
|
|
ParseIPv4(&Settings->ipv4_rgx_address, PSTR(WIFI_RGX_IP_ADDRESS));
|
|
ParseIPv4(&Settings->ipv4_rgx_subnetmask, PSTR(WIFI_RGX_SUBNETMASK));
|
|
SettingsUpdateText(SET_RGX_SSID, PSTR(WIFI_RGX_SSID));
|
|
SettingsUpdateText(SET_RGX_PASSWORD, PSTR(WIFI_RGX_PASSWORD));
|
|
}
|
|
if (Settings->version < 0x09050007) {
|
|
#ifdef DISABLE_REFERER_CHK
|
|
Settings->flag5.disable_referer_chk |= false;
|
|
#else
|
|
Settings->flag5.disable_referer_chk |= true;
|
|
#endif
|
|
}
|
|
if (Settings->version < 0x09050009) {
|
|
memset(&Settings->energy_kWhtoday_ph, 0, 36);
|
|
memset(&RtcSettings.energy_kWhtoday_ph, 0, 24);
|
|
}
|
|
if (Settings->version < 0x0A000003) {
|
|
if (0 == Settings->param[P_ARP_GRATUITOUS]) {
|
|
Settings->param[P_ARP_GRATUITOUS] = WIFI_ARP_INTERVAL;
|
|
#ifdef USE_TLS
|
|
for (uint32_t i = 0; i < 20; i++) {
|
|
if (Settings->mqtt_fingerprint[0][i]) {
|
|
Settings->flag5.tls_use_fingerprint = true; // if the fingerprint1 is non null we expect it to be actually used
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
if (Settings->version < 0x0A010003) {
|
|
Settings->sserial_config = Settings->serial_config;
|
|
}
|
|
if (Settings->version < 0x0A010006) {
|
|
Settings->web_time_start = 0;
|
|
Settings->web_time_end = 0;
|
|
}
|
|
if (Settings->version < 0x0B000003) { // 11.0.0.3
|
|
memcpy(Settings->pulse_timer, Settings->ex_pulse_timer, 16);
|
|
}
|
|
|
|
Settings->version = VERSION;
|
|
SettingsSave(1);
|
|
}
|
|
|
|
}
|