Browse Source

Restore settings & reset via HTTP

fastled
Xose Pérez 7 years ago
parent
commit
e11dc5558f
5 changed files with 105 additions and 41 deletions
  1. +4
    -1
      code/espurna/config/general.h
  2. +1
    -0
      code/espurna/config/prototypes.h
  3. +22
    -0
      code/espurna/settings.ino
  4. +55
    -0
      code/espurna/web.ino
  5. +23
    -40
      code/espurna/ws.ino

+ 4
- 1
code/espurna/config/general.h View File

@ -140,6 +140,7 @@
#define CUSTOM_RESET_MQTT 4 // Reset via MQTT
#define CUSTOM_RESET_RPC 5 // Reset via RPC (HTTP)
#define CUSTOM_RESET_OTA 6 // Reset after successful OTA update
#define CUSTOM_RESET_HTTP 7 // Reset via HTTP GET
#define CUSTOM_RESET_NOFUSS 8 // Reset after successful NOFUSS update
#define CUSTOM_RESET_UPGRADE 9 // Reset after update from web interface
#define CUSTOM_RESET_FACTORY 10 // Factory reset from terminal
@ -154,13 +155,15 @@ PROGMEM const char custom_reset_terminal[] = "Reboot from terminal";
PROGMEM const char custom_reset_mqtt[] = "Reboot from MQTT";
PROGMEM const char custom_reset_rpc[] = "Reboot from RPC";
PROGMEM const char custom_reset_ota[] = "Reboot after successful OTA update";
PROGMEM const char custom_reset_http[] = "Reboot from HTTP";
PROGMEM const char custom_reset_nofuss[] = "Reboot after successful NoFUSS update";
PROGMEM const char custom_reset_upgrade[] = "Reboot after successful web update";
PROGMEM const char custom_reset_factory[] = "Factory reset";
PROGMEM const char* const custom_reset_string[] = {
custom_reset_hardware, custom_reset_web, custom_reset_terminal,
custom_reset_mqtt, custom_reset_rpc, custom_reset_ota,
custom_reset_nofuss, custom_reset_upgrade, custom_reset_factory
custom_reset_http, custom_reset_nofuss, custom_reset_upgrade,
custom_reset_factory
};
//------------------------------------------------------------------------------


+ 1
- 0
code/espurna/config/prototypes.h View File

@ -46,6 +46,7 @@ template<typename T> bool setSetting(const String& key, T value);
template<typename T> bool setSetting(const String& key, unsigned int index, T value);
template<typename T> String getSetting(const String& key, T defaultValue);
template<typename T> String getSetting(const String& key, unsigned int index, T defaultValue);
bool settingsRestore(JsonObject& data);
// -----------------------------------------------------------------------------
// Domoticz


+ 22
- 0
code/espurna/settings.ino View File

@ -90,6 +90,28 @@ String settingsKeyName(unsigned int index) {
}
bool settingsRestore(JsonObject& data) {
const char* app = data["app"];
if (strcmp(app, APP_NAME) != 0) return false;
for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) {
EEPROM.write(i, 0xFF);
}
for (auto element : data) {
if (strcmp(element.key, "app") == 0) continue;
if (strcmp(element.key, "version") == 0) continue;
setSetting(element.key, element.value.as<char*>());
}
saveSettings();
DEBUG_MSG_P(PSTR("[SETTINGS] Settings restored successfully\n"));
return true;
}
void settingsFactoryReset() {
for (unsigned int i = 0; i < SPI_FLASH_SEC_SIZE; i++) {
EEPROM.write(i, 0xFF);


+ 55
- 0
code/espurna/web.ino View File

@ -28,11 +28,18 @@ Copyright (C) 2016-2017 by Xose Pérez <xose dot perez at gmail dot com>
AsyncWebServer * _server;
char _last_modified[50];
std::vector<uint8_t> * _webConfigBuffer;
bool _webConfigSuccess = false;
// -----------------------------------------------------------------------------
// HOOKS
// -----------------------------------------------------------------------------
void _onReset(AsyncWebServerRequest *request) {
deferredReset(100, CUSTOM_RESET_HTTP);
request->send(200);
}
void _onGetConfig(AsyncWebServerRequest *request) {
webLog(request);
@ -59,6 +66,52 @@ void _onGetConfig(AsyncWebServerRequest *request) {
}
void _onPostConfig(AsyncWebServerRequest *request) {
webLog(request);
if (!_authenticate(request)) return request->requestAuthentication(getSetting("hostname").c_str());
request->send(_webConfigSuccess ? 200 : 400);
}
void _onPostConfigData(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
// No buffer
if (final && (index == 0)) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char *) data);
if (root.success()) _webConfigSuccess = settingsRestore(root);
return;
}
// Buffer start => reset
if (index == 0) if (_webConfigBuffer) delete _webConfigBuffer;
// init buffer if it doesn't exist
if (!_webConfigBuffer) {
_webConfigBuffer = new std::vector<uint8_t>();
_webConfigSuccess = false;
}
// Copy
if (len > 0) {
_webConfigBuffer->reserve(_webConfigBuffer->size() + len);
_webConfigBuffer->insert(_webConfigBuffer->end(), data, data + len);
}
// Ending
if (final) {
_webConfigBuffer->push_back(0);
// Parse JSON
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char *) _webConfigBuffer->data());
if (root.success()) _webConfigSuccess = settingsRestore(root);
delete _webConfigBuffer;
}
}
#if WEB_EMBEDDED
void _onHome(AsyncWebServerRequest *request) {
@ -250,7 +303,9 @@ void webSetup() {
#if WEB_EMBEDDED
_server->on("/index.html", HTTP_GET, _onHome);
#endif
_server->on("/reset", HTTP_GET, _onReset);
_server->on("/config", HTTP_GET, _onGetConfig);
_server->on("/config", HTTP_POST | HTTP_PUT, _onPostConfig, _onPostConfigData);
_server->on("/upgrade", HTTP_POST, _onUpgrade, _onUpgradeData);
// Serve static files


+ 23
- 40
code/espurna/ws.ino View File

@ -55,7 +55,7 @@ bool _wsStore(String key, JsonArray& value) {
bool changed = false;
unsigned char index = 0;
for (auto element : (JsonArray&) value) {
for (auto element : value) {
if (_wsStore(key + index, element.as<String>())) changed = true;
index++;
}
@ -66,7 +66,6 @@ bool _wsStore(String key, JsonArray& value) {
changed = true;
}
if (changed) Serial.println(key);
return changed;
}
@ -89,51 +88,40 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
// Check actions -----------------------------------------------------------
if (root.containsKey("action")) {
const char* action = root["action"];
if (action) {
String action = root["action"];
JsonObject& data = root.containsKey("data") ? root["data"] : jsonBuffer.createObject();
DEBUG_MSG_P(PSTR("[WEBSOCKET] Requested action: %s\n"), action);
DEBUG_MSG_P(PSTR("[WEBSOCKET] Requested action: %s\n"), action.c_str());
if (strcmp(action, "reboot") == 0) deferredReset(100, CUSTOM_RESET_WEB);
if (strcmp(action, "reconnect") == 0) _web_defer.once_ms(100, wifiDisconnect);
// Callbacks
for (unsigned char i = 0; i < _ws_on_action_callbacks.size(); i++) {
(_ws_on_action_callbacks[i])(action.c_str(), data);
}
if (action.equals("reboot")) deferredReset(100, CUSTOM_RESET_WEB);
if (action.equals("reconnect")) _web_defer.once_ms(100, wifiDisconnect);
if (action.equals("restore")) {
JsonObject& data = root["data"];
if (data.success()) {
if (!data.containsKey("app") || (data["app"] != APP_NAME)) {
wsSend_P(client_id, PSTR("{\"message\": 4}"));
return;
}
for (unsigned int i = EEPROM_DATA_END; i < SPI_FLASH_SEC_SIZE; i++) {
EEPROM.write(i, 0xFF);
// Callbacks
for (unsigned char i = 0; i < _ws_on_action_callbacks.size(); i++) {
(_ws_on_action_callbacks[i])(action, data);
}
for (auto element : data) {
if (strcmp(element.key, "app") == 0) continue;
if (strcmp(element.key, "version") == 0) continue;
setSetting(element.key, element.value.as<char*>());
// Restore configuration via websockets
if (strcmp(action, "restore") == 0) {
if (settingsRestore(data)) {
wsSend_P(client_id, PSTR("{\"message\": 5}"));
} else {
wsSend_P(client_id, PSTR("{\"message\": 4}"));
}
}
saveSettings();
wsSend_P(client_id, PSTR("{\"message\": 5}"));
}
};
// Check configuration -----------------------------------------------------
if (root.containsKey("config") && root["config"].is<JsonObject&>()) {
JsonObject& config = root["config"];
if (config.success()) {
JsonObject& config = root["config"];
DEBUG_MSG_P(PSTR("[WEBSOCKET] Parsing configuration data\n"));
String adminPass;
@ -179,7 +167,6 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
powerCalibrate(POWER_MAGNITUDE_ACTIVE, expected);
save = true;
}
delSetting(key);
continue;
}
@ -188,7 +175,6 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
powerCalibrate(POWER_MAGNITUDE_VOLTAGE, expected);
save = true;
}
delSetting(key);
continue;
}
@ -197,7 +183,6 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
powerCalibrate(POWER_MAGNITUDE_CURRENT, expected);
save = true;
}
delSetting(key);
continue;
}
@ -206,7 +191,6 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
powerCalibrate(POWER_MAGNITUDE_POWER_FACTOR, expected);
save = true;
}
delSetting(key);
continue;
}
@ -214,9 +198,7 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
if (value.as<bool>()) {
powerResetCalibration();
save = true;
Serial.println(key);
}
delSetting(key);
continue;
}
@ -273,10 +255,11 @@ void _wsParse(AsyncWebSocketClient *client, uint8_t * payload, size_t length) {
void _wsOnStart(JsonObject& root) {
bool changePassword = false;
#if WEB_FORCE_PASS_CHANGE
String adminPass = getSetting("adminPass", ADMIN_PASS);
if (adminPass.equals(ADMIN_PASS)) changePassword = true;
bool changePassword = adminPass.equals(ADMIN_PASS);
#else
bool changePassword = false;
#endif
if (changePassword) {


Loading…
Cancel
Save