Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Factory Reset option #376

Merged
merged 1 commit into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ In a browser navigate to the IP address assigned to the ESP32.

- Type [4 DIGIT CODE] to confirm unpair: Set to the shown randomly generated code to unpair the Nuki Lock or Opener from the Nuki Hub.

#### Factory reset Nuki Hub

- Type [4 DIGIT CODE] to confirm factory reset: Set to the shown randomly generated code to reset all Nuki Hub settings to default and unpair Nuki Lock and/or Opener. Optionally also reset WiFi settings to default by enabling the checkbox.

### GPIO Configuration

- Gpio [2-33]: See the "[GPIO lock control](#gpio-lock-control-optional)" section of this README.
Expand Down
3 changes: 3 additions & 0 deletions src/RestartReason.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum class RestartReason
OTAAborted,
OTAUnknownState,
DeviceUnpaired,
NukiHubReset,
NotApplicable
};

Expand Down Expand Up @@ -100,6 +101,8 @@ inline static String getRestartReason()
return "OTAUnknownState";
case RestartReason::DeviceUnpaired:
return "DeviceUnpaired";
case RestartReason::NukiHubReset:
return "NukiHubFactoryReset";
case RestartReason::NotApplicable:
return "NotApplicable";
default:
Expand Down
97 changes: 90 additions & 7 deletions src/WebCfgServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "Config.h"
#include "RestartReason.h"
#include <esp_task_wdt.h>
#include <esp_wifi.h>

WebCfgServer::WebCfgServer(NukiWrapper* nuki, NukiOpenerWrapper* nukiOpener, Network* network, Gpio* gpio, EthServer* ethServer, Preferences* preferences, bool allowRestartToPortal)
: _server(ethServer),
Expand Down Expand Up @@ -140,6 +141,13 @@ void WebCfgServer::initialize()

processUnpair(true);
});
_server.on("/factoryreset", [&]() {
if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server.requestAuthentication();
}

processFactoryReset();
});
_server.on("/wifimanager", [&]() {
if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server.requestAuthentication();
Expand Down Expand Up @@ -489,7 +497,7 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "TSKNUKI")
{
if(value.toInt() > 8191 && value.toInt() < 32769)
{
{
_preferences->putInt(preference_task_size_nuki, value.toInt());
configChanged = true;
}
Expand All @@ -505,35 +513,35 @@ bool WebCfgServer::processArgs(String& message)
else if(key == "ALMAX")
{
if(value.toInt() > 0 && value.toInt() < 51)
{
{
_preferences->putInt(preference_authlog_max_entries, value.toInt());
configChanged = true;
}
}
else if(key == "KPMAX")
{
if(value.toInt() > 0 && value.toInt() < 101)
{
{
_preferences->putInt(preference_keypad_max_entries, value.toInt());
configChanged = true;
}
}
else if(key == "TCMAX")
{
if(value.toInt() > 0 && value.toInt() < 51)
{
{
_preferences->putInt(preference_timecontrol_max_entries, value.toInt());
configChanged = true;
}
}
else if(key == "BUFFSIZE")
{
if(value.toInt() > 4095 && value.toInt() < 32769)
{
{
_preferences->putInt(preference_buffer_size, value.toInt());
configChanged = true;
}
}
}
else if(key == "BTLPRST")
{
_preferences->putBool(preference_enable_bootloop_reset, (value == "1"));
Expand Down Expand Up @@ -1236,6 +1244,18 @@ void WebCfgServer::buildCredHtml(String &response)
response.concat("</table>");
response.concat("<br><button type=\"submit\">OK</button></form>");
}

response.concat("<br><br><h3>Factory reset Nuki Hub</h3>");
response.concat("<h4 style=\"color: #ff0000\">This will reset all settings to default and unpair Nuki Lock and/or Opener. Optionally will also reset WiFi settings and reopen WiFi manager portal.</h4>");
response.concat("<form method=\"post\" action=\"/factoryreset\">");
response.concat("<table>");
String message = "Type ";
message.concat(_confirmCode);
message.concat(" to confirm factory reset");
printInputField(response, "CONFIRMTOKEN", message.c_str(), "", 10);
printCheckBox(response, "WIFI", "Also reset WiFi settings", false, "");
response.concat("</table>");
response.concat("<br><button type=\"submit\">OK</button></form>");
response.concat("</body></html>");
}

Expand Down Expand Up @@ -1862,7 +1882,7 @@ void WebCfgServer::buildInfoHtml(String &response)
response.concat("Network device: ");
response.concat(_network->networkDeviceName());
response.concat("\n");

if(_network->networkDeviceName() == "Built-in Wi-Fi")
{
response.concat("BSSID of AP: ");
Expand Down Expand Up @@ -1941,6 +1961,69 @@ void WebCfgServer::processUnpair(bool opener)
restartEsp(RestartReason::DeviceUnpaired);
}

void WebCfgServer::processFactoryReset()
{
bool resetWifi = false;
String response = "";
if(_server.args() == 0)
{
buildConfirmHtml(response, "Confirm code is invalid.", 3);
_server.send(200, "text/html", response);
return;
}
else
{
String key = _server.argName(0);
String value = _server.arg(0);

if(key != "CONFIRMTOKEN" || value != _confirmCode)
{
buildConfirmHtml(response, "Confirm code is invalid.", 3);
_server.send(200, "text/html", response);
return;
}

String key2 = _server.argName(2);
String value2 = _server.arg(2);

if(key2 == "WIFI" && value2 == "1")
{
resetWifi = true;
buildConfirmHtml(response, "Factory resetting Nuki Hub, unpairing Nuki Lock and Nuki Opener and resetting WiFi.", 3);
}
else buildConfirmHtml(response, "Factory resetting Nuki Hub, unpairing Nuki Lock and Nuki Opener.", 3);
}

_server.send(200, "text/html", response);
waitAndProcess(false, 2000);

if(_nuki != nullptr)
{
_nuki->disableHASS();
_nuki->unpair();
}
if(_nukiOpener != nullptr)
{
_nukiOpener->disableHASS();
_nukiOpener->unpair();
}

_preferences->clear();

if(resetWifi)
{
wifi_config_t current_conf;
esp_wifi_get_config((wifi_interface_t)ESP_IF_WIFI_STA, &current_conf);
memset(current_conf.sta.ssid, 0, sizeof(current_conf.sta.ssid));
memset(current_conf.sta.password, 0, sizeof(current_conf.sta.password));
esp_wifi_set_config((wifi_interface_t)ESP_IF_WIFI_STA, &current_conf);
_network->reconfigureDevice();
}

waitAndProcess(false, 3000);
restartEsp(RestartReason::NukiHubReset);
}

void WebCfgServer::buildHtmlHeader(String &response)
{
response.concat("<html><head>");
Expand Down
1 change: 1 addition & 0 deletions src/WebCfgServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class WebCfgServer
void sendCss();
void sendFavicon();
void processUnpair(bool opener);
void processFactoryReset();

void buildHtmlHeader(String& response);
void printInputField(String& response, const char* token, const char* description, const char* value, const size_t& maxLength, const bool& isPassword = false, const bool& showLengthRestriction = false);
Expand Down