mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-02 04:05:14 +00:00
Compare commits
4 Commits
f8257de0dd
...
2c8eb534af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c8eb534af | ||
|
|
5210fab4cb | ||
|
|
49787d27f1 | ||
|
|
dfe7b46461 |
6
Makefile
6
Makefile
@@ -52,13 +52,13 @@ INCLUDES := src/core src/devices src/web src/test lib_standalone lib/* lib/semv
|
|||||||
LIBRARIES :=
|
LIBRARIES :=
|
||||||
|
|
||||||
CPPCHECK = cppcheck
|
CPPCHECK = cppcheck
|
||||||
CHECKFLAGS = -q --force --std=gnu++17
|
CHECKFLAGS = -q --force --std=gnu++20
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Languages Standard
|
# Languages Standard
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
C_STANDARD := -std=c17
|
C_STANDARD := -std=c20
|
||||||
CXX_STANDARD := -std=gnu++17
|
CXX_STANDARD := -std=gnu++20
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Defined Symbols
|
# Defined Symbols
|
||||||
|
|||||||
@@ -1428,11 +1428,306 @@ void System::show_system(uuid::console::Shell & shell) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// see if there is a restore of an older settings file that needs to be applied
|
// see if there is a restore of an older settings file that needs to be applied
|
||||||
// note there can be only one file at a time
|
// note there can be only one file at a time
|
||||||
bool System::check_restore() {
|
bool System::check_restore() {
|
||||||
bool reboot_required = false; // true if we need to reboot
|
bool reboot_required = false; // true if we need to reboot
|
||||||
|
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
|
File new_file = LittleFS.open(TEMP_FILENAME_PATH);
|
||||||
|
if (new_file) {
|
||||||
|
JsonDocument jsonDocument;
|
||||||
|
DeserializationError error = deserializeJson(jsonDocument, new_file);
|
||||||
|
if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) {
|
||||||
|
JsonObject input = jsonDocument.as<JsonObject>();
|
||||||
|
// see what type of file it is, either settings or customization. anything else is ignored
|
||||||
|
std::string settings_type = input["type"];
|
||||||
|
LOG_INFO("Restoring '%s' settings...", settings_type.c_str());
|
||||||
|
|
||||||
|
// system backup, which is a consolidated json object with all the settings files
|
||||||
|
if (settings_type == "systembackup") {
|
||||||
|
reboot_required = true;
|
||||||
|
JsonArray sections = input["systembackup"].as<JsonArray>();
|
||||||
|
for (JsonObject section : sections) {
|
||||||
|
std::string section_type = section["type"];
|
||||||
|
LOG_DEBUG("Restoring '%s' section...", section_type.c_str());
|
||||||
|
if (section_type == "settings") {
|
||||||
|
saveSettings(NETWORK_SETTINGS_FILE, section);
|
||||||
|
saveSettings(AP_SETTINGS_FILE, section);
|
||||||
|
saveSettings(MQTT_SETTINGS_FILE, section);
|
||||||
|
saveSettings(NTP_SETTINGS_FILE, section);
|
||||||
|
saveSettings(SECURITY_SETTINGS_FILE, section);
|
||||||
|
saveSettings(EMSESP_SETTINGS_FILE, section);
|
||||||
|
}
|
||||||
|
if (section_type == "schedule") {
|
||||||
|
saveSettings(EMSESP_SCHEDULER_FILE, section);
|
||||||
|
}
|
||||||
|
if (section_type == "customizations") {
|
||||||
|
saveSettings(EMSESP_CUSTOMIZATION_FILE, section);
|
||||||
|
}
|
||||||
|
if (section_type == "entities") {
|
||||||
|
saveSettings(EMSESP_CUSTOMENTITY_FILE, section);
|
||||||
|
}
|
||||||
|
if (section_type == "modules") {
|
||||||
|
saveSettings(EMSESP_MODULES_FILE, section);
|
||||||
|
}
|
||||||
|
if (section_type == "customSupport") {
|
||||||
|
// it's a custom support, extract json and write to /config/customSupport.json file
|
||||||
|
File customSupportFile = LittleFS.open(EMSESP_CUSTOMSUPPORT_FILE, "w");
|
||||||
|
if (customSupportFile) {
|
||||||
|
serializeJson(section, customSupportFile);
|
||||||
|
customSupportFile.close();
|
||||||
|
LOG_INFO("Custom support file updated");
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to save custom support file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section_type == "nvs") {
|
||||||
|
// Restore NVS values
|
||||||
|
JsonArray nvs_entries = section["nvs"].as<JsonArray>();
|
||||||
|
for (JsonObject entry : nvs_entries) {
|
||||||
|
std::string key = entry["key"] | "";
|
||||||
|
int type = entry["type"] | NVS_TYPE_ANY;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case NVS_TYPE_I8:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
int8_t v = entry["value"];
|
||||||
|
EMSESP::nvs_.putChar(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_U8:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
uint8_t v = entry["value"];
|
||||||
|
EMSESP::nvs_.putUChar(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_I32:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
int32_t v = entry["value"];
|
||||||
|
EMSESP::nvs_.putInt(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_U32:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
uint32_t v = entry["value"];
|
||||||
|
EMSESP::nvs_.putUInt(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_I64:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
int64_t v = entry["value"];
|
||||||
|
EMSESP::nvs_.putLong64(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_U64:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
uint64_t v = entry["value"];
|
||||||
|
EMSESP::nvs_.putULong64(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_BLOB:
|
||||||
|
// used for double values
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
double v = entry["value"];
|
||||||
|
EMSESP::nvs_.putDouble(key.c_str(), v);
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %d", key.c_str(), v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NVS_TYPE_STR:
|
||||||
|
case NVS_TYPE_ANY:
|
||||||
|
default:
|
||||||
|
if (entry["value"].is<JsonVariantConst>()) {
|
||||||
|
std::string v = entry["value"];
|
||||||
|
EMSESP::nvs_.putString(key.c_str(), v.c_str());
|
||||||
|
LOG_DEBUG("Restored NVS value: %s = %s", key.c_str(), v.c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's a single settings file. Parse each section separately. If it's system related it will require a reboot
|
||||||
|
else if (settings_type == "settings") {
|
||||||
|
reboot_required = saveSettings(NETWORK_SETTINGS_FILE, input);
|
||||||
|
reboot_required |= saveSettings(AP_SETTINGS_FILE, input);
|
||||||
|
reboot_required |= saveSettings(MQTT_SETTINGS_FILE, input);
|
||||||
|
reboot_required |= saveSettings(NTP_SETTINGS_FILE, input);
|
||||||
|
reboot_required |= saveSettings(SECURITY_SETTINGS_FILE, input);
|
||||||
|
reboot_required |= saveSettings(EMSESP_SETTINGS_FILE, input);
|
||||||
|
} else if (settings_type == "customizations") {
|
||||||
|
saveSettings(EMSESP_CUSTOMIZATION_FILE, input);
|
||||||
|
} else if (settings_type == "schedule") {
|
||||||
|
saveSettings(EMSESP_SCHEDULER_FILE, input);
|
||||||
|
} else if (settings_type == "entities") {
|
||||||
|
saveSettings(EMSESP_CUSTOMENTITY_FILE, input);
|
||||||
|
} else if (settings_type == "customSupport") {
|
||||||
|
// it's a custom support file - save it to /config
|
||||||
|
new_file.close();
|
||||||
|
if (LittleFS.rename(TEMP_FILENAME_PATH, EMSESP_CUSTOMSUPPORT_FILE)) {
|
||||||
|
LOG_INFO("Custom support file stored");
|
||||||
|
return false; // no need to reboot
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Failed to save custom support file");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Unrecognized file uploaded");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("Unrecognized file uploaded, not json.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// close (just in case) and remove the temp file
|
||||||
|
new_file.close();
|
||||||
|
LittleFS.remove(TEMP_FILENAME_PATH);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return reboot_required;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle upgrades from previous versions
|
||||||
|
// this function will not be called on a clean install, with no settings files yet created
|
||||||
|
// returns true if we need a reboot
|
||||||
|
bool System::check_upgrade() {
|
||||||
|
bool missing_version = true;
|
||||||
|
std::string settingsVersion;
|
||||||
|
|
||||||
|
// fetch current version from settings file
|
||||||
|
EMSESP::webSettingsService.read([&](WebSettings const & settings) { settingsVersion = settings.version.c_str(); });
|
||||||
|
|
||||||
|
// see if we're missing a version, will be < 3.5.0b13 from Dec 23 2022
|
||||||
|
missing_version = (settingsVersion.empty() || (settingsVersion.length() < 5));
|
||||||
|
if (missing_version) {
|
||||||
|
LOG_WARNING("No version information found. Assuming version 3.5.0");
|
||||||
|
settingsVersion = "3.5.0"; // this was the last stable version without version info
|
||||||
|
}
|
||||||
|
|
||||||
|
version::Semver200_version settings_version(settingsVersion);
|
||||||
|
version::Semver200_version this_version(EMSESP_APP_VERSION);
|
||||||
|
|
||||||
|
std::string settings_version_type = settings_version.prerelease().empty() ? "" : ("-" + settings_version.prerelease());
|
||||||
|
std::string this_version_type = this_version.prerelease().empty() ? "" : ("-" + this_version.prerelease());
|
||||||
|
bool save_version = true;
|
||||||
|
bool reboot_required = false;
|
||||||
|
|
||||||
|
LOG_DEBUG("Checking for version upgrades from v%d.%d.%d%s",
|
||||||
|
settings_version.major(),
|
||||||
|
settings_version.minor(),
|
||||||
|
settings_version.patch(),
|
||||||
|
settings_version_type.c_str());
|
||||||
|
|
||||||
|
// compare versions
|
||||||
|
if (this_version > settings_version) {
|
||||||
|
// we need to do an upgrade
|
||||||
|
if (missing_version) {
|
||||||
|
LOG_NOTICE("Upgrading to version %d.%d.%d%s", this_version.major(), this_version.minor(), this_version.patch(), this_version_type.c_str());
|
||||||
|
} else {
|
||||||
|
LOG_NOTICE("Upgrading from version %d.%d.%d%s to %d.%d.%d%s",
|
||||||
|
settings_version.major(),
|
||||||
|
settings_version.minor(),
|
||||||
|
settings_version.patch(),
|
||||||
|
settings_version_type.c_str(),
|
||||||
|
this_version.major(),
|
||||||
|
this_version.minor(),
|
||||||
|
this_version.patch(),
|
||||||
|
this_version_type.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're coming from 3.4.4 or 3.5.0b14 which had no version stored then we need to apply new settings
|
||||||
|
if (missing_version) {
|
||||||
|
LOG_INFO("Upgrade: Setting MQTT Entity ID format to older v3.4 format (0)");
|
||||||
|
EMSESP::esp32React.getMqttSettingsService()->update([&](MqttSettings & mqttSettings) {
|
||||||
|
mqttSettings.entity_format = Mqtt::entityFormat::SINGLE_LONG; // use old Entity ID format from v3.4
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
});
|
||||||
|
} else if (settings_version.major() == 3 && settings_version.minor() <= 6) {
|
||||||
|
EMSESP::esp32React.getMqttSettingsService()->update([&](MqttSettings & mqttSettings) {
|
||||||
|
if (mqttSettings.entity_format == 1) {
|
||||||
|
mqttSettings.entity_format = Mqtt::entityFormat::SINGLE_OLD; // use old Entity ID format from v3.6
|
||||||
|
LOG_INFO("Upgrade: Setting MQTT Entity ID format to v3.6 format (3)");
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
} else if (mqttSettings.entity_format == 2) {
|
||||||
|
mqttSettings.entity_format = Mqtt::entityFormat::MULTI_OLD; // use old Entity ID format from v3.6
|
||||||
|
LOG_INFO("Upgrade: Setting MQTT Entity ID format to v3.6 format (4)");
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
|
return StateUpdateResult::UNCHANGED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// changes pre < v3.7.0
|
||||||
|
if (settings_version.major() == 3 && settings_version.minor() < 7) {
|
||||||
|
// network changes
|
||||||
|
// 1) WiFi Tx Power is now using the value * 4 (was 20)
|
||||||
|
// 2) WiFi sleep is now off by default (was on)
|
||||||
|
EMSESP::esp32React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
|
||||||
|
auto changed = StateUpdateResult::UNCHANGED;
|
||||||
|
if (networkSettings.tx_power == 20) {
|
||||||
|
networkSettings.tx_power = WIFI_POWER_19_5dBm; // use 19.5 as we don't have 20 anymore
|
||||||
|
LOG_INFO("Upgrade: Setting WiFi TX Power to Auto");
|
||||||
|
changed = StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
|
if (networkSettings.nosleep != true) {
|
||||||
|
networkSettings.nosleep = true;
|
||||||
|
LOG_INFO("Upgrade: Disabling WiFi nosleep");
|
||||||
|
changed = StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// changes to application settings
|
||||||
|
EMSESP::webSettingsService.update([&](WebSettings & settings) {
|
||||||
|
// force web buffer to 25 for those boards without psram
|
||||||
|
if ((EMSESP::system_.PSram() == 0) && (settings.weblog_buffer != 25)) {
|
||||||
|
settings.weblog_buffer = 25;
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
|
return StateUpdateResult::UNCHANGED;
|
||||||
|
});
|
||||||
|
} else if (this_version < settings_version) {
|
||||||
|
// downgrading
|
||||||
|
LOG_NOTICE("Downgrading from version %d.%d.%d%s to version %d.%d.%d%s",
|
||||||
|
settings_version.major(),
|
||||||
|
settings_version.minor(),
|
||||||
|
settings_version.patch(),
|
||||||
|
settings_version_type.c_str(),
|
||||||
|
this_version.major(),
|
||||||
|
this_version.minor(),
|
||||||
|
this_version.patch(),
|
||||||
|
this_version_type.c_str());
|
||||||
|
} else {
|
||||||
|
save_version = false; // same version, do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we did a change, set the new version and save it, no need to reboot
|
||||||
|
if (save_version) {
|
||||||
|
EMSESP::webSettingsService.update([&](WebSettings & settings) {
|
||||||
|
settings.version = EMSESP_APP_VERSION;
|
||||||
|
LOG_DEBUG("Upgrade: Setting version to %s", EMSESP_APP_VERSION);
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reboot_required) {
|
||||||
|
LOG_INFO("Upgrade: Rebooting to apply changes");
|
||||||
|
return true; // need reboot
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // no reboot required
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
// map each config filename to its human-readable section key
|
// map each config filename to its human-readable section key
|
||||||
static const std::pair<const char *, const char *> SECTION_MAP[] = {
|
static const std::pair<const char *, const char *> SECTION_MAP[] = {
|
||||||
@@ -3184,4 +3479,3 @@ static const std::pair<const char *, const char *> SECTION_MAP[] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|
||||||
@@ -352,7 +352,7 @@ bool WebSchedulerService::command(const char * name, const std::string & command
|
|||||||
// parse json
|
// parse json
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
|
if (deserializeJson(doc, cmd) == DeserializationError::Ok) {
|
||||||
HTTPClient http;
|
// HTTPClient http;
|
||||||
std::string url = doc["url"] | "";
|
std::string url = doc["url"] | "";
|
||||||
// for a GET with parameters replace commands with values
|
// for a GET with parameters replace commands with values
|
||||||
// don't search the complete url, it may contain a devicename in path
|
// don't search the complete url, it may contain a devicename in path
|
||||||
|
|||||||
Reference in New Issue
Block a user