8 Commits

Author SHA1 Message Date
Yurii
43c065b97a Merge branch 'master' into 1.5.0-dev 2024-12-04 07:56:19 +03:00
Yurii
5c1e967fdc refactor: improved display of sensors on Dashboard 2024-12-04 06:09:20 +03:00
Yurii
105a79f72c refactor: optimization of OT requests for CH2 2024-12-04 05:55:01 +03:00
Yurii
50280f6db3 fix: negative temperature values from BLE devices 2024-12-04 05:36:04 +03:00
Yurii
c97e50669c fix: typo in purpose of sensors for emergency mode 2024-12-04 05:35:19 +03:00
Yurii
43fd095714 fix: digest auth changed to basic
Digest auth not working on ios #99
2024-12-02 06:26:03 +03:00
Yurii
1eb10563ed chore: update readme 2024-11-30 23:58:54 +03:00
Yurii
f4af237472 chore: bump version to 1.4.6 2024-11-16 14:19:40 +03:00
13 changed files with 138 additions and 112 deletions

View File

@@ -82,3 +82,6 @@ All available information and instructions can be found in the wiki:
## Debug ## Debug
To display DEBUG messages you must enable debug in settings (switch is disabled by default). To display DEBUG messages you must enable debug in settings (switch is disabled by default).
You can connect via Telnet to read messages. IP: ESP8266 ip, port: 23 You can connect via Telnet to read messages. IP: ESP8266 ip, port: 23
___
This project is tested with BrowserStack.

View File

@@ -14,7 +14,7 @@ extra_configs = secrets.default.ini
core_dir = .pio core_dir = .pio
[env] [env]
version = 1.5.0-alpha version = 1.5.0
framework = arduino framework = arduino
lib_deps = lib_deps =
bblanchon/ArduinoJson@^7.1.0 bblanchon/ArduinoJson@^7.1.0

View File

@@ -218,13 +218,13 @@ protected:
// set outdoor sensor flag // set outdoor sensor flag
if (settings.equitherm.enabled) { if (settings.equitherm.enabled) {
if (!Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP)) { if (!Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::OUTDOOR_TEMP)) {
emergencyFlags |= 0b00000001; emergencyFlags |= 0b00000001;
} }
} }
// set indoor sensor flags // set indoor sensor flags
if (!Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::OUTDOOR_TEMP)) { if (!Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP)) {
if (!settings.equitherm.enabled && settings.pid.enabled) { if (!settings.equitherm.enabled && settings.pid.enabled) {
emergencyFlags |= 0b00000010; emergencyFlags |= 0b00000010;
} }

View File

@@ -1038,7 +1038,8 @@ protected:
} }
// Set CH2 temp // Set CH2 temp
if (vars.master.ch2.enabled && !settings.opentherm.nativeHeatingControl) { if (!settings.opentherm.nativeHeatingControl && vars.master.ch2.enabled) {
if (settings.opentherm.heatingCh1ToCh2 || settings.opentherm.dhwToCh2) {
// Converted target CH2 temp // Converted target CH2 temp
float convertedTemp = convertTemp( float convertedTemp = convertTemp(
vars.master.ch2.targetTemp, vars.master.ch2.targetTemp,
@@ -1061,6 +1062,7 @@ protected:
} }
} }
} }
}
void initialize() { void initialize() {
// Not all boilers support these, only try once when the boiler becomes connected // Not all boilers support these, only try once when the boiler becomes connected

View File

@@ -108,8 +108,8 @@ protected:
// dashboard page // dashboard page
auto dashboardPage = (new StaticPage("/dashboard.html", &LittleFS, F("/pages/dashboard.html"), PORTAL_CACHE)) auto dashboardPage = (new StaticPage("/dashboard.html", &LittleFS, F("/pages/dashboard.html"), PORTAL_CACHE))
->setBeforeSendCallback([this]() { ->setBeforeSendCallback([this]() {
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->requestAuthentication(DIGEST_AUTH); this->webServer->requestAuthentication(BASIC_AUTH);
return false; return false;
} }
@@ -119,12 +119,10 @@ protected:
// restart // restart
this->webServer->on(F("/restart.html"), HTTP_GET, [this]() { this->webServer->on(F("/restart.html"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { this->webServer->requestAuthentication(BASIC_AUTH);
this->webServer->send(401);
return; return;
} }
}
vars.actions.restart = true; vars.actions.restart = true;
this->webServer->sendHeader(F("Location"), "/"); this->webServer->sendHeader(F("Location"), "/");
@@ -134,8 +132,8 @@ protected:
// network settings page // network settings page
auto networkPage = (new StaticPage("/network.html", &LittleFS, F("/pages/network.html"), PORTAL_CACHE)) auto networkPage = (new StaticPage("/network.html", &LittleFS, F("/pages/network.html"), PORTAL_CACHE))
->setBeforeSendCallback([this]() { ->setBeforeSendCallback([this]() {
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->requestAuthentication(DIGEST_AUTH); this->webServer->requestAuthentication(BASIC_AUTH);
return false; return false;
} }
@@ -146,8 +144,8 @@ protected:
// settings page // settings page
auto settingsPage = (new StaticPage("/settings.html", &LittleFS, F("/pages/settings.html"), PORTAL_CACHE)) auto settingsPage = (new StaticPage("/settings.html", &LittleFS, F("/pages/settings.html"), PORTAL_CACHE))
->setBeforeSendCallback([this]() { ->setBeforeSendCallback([this]() {
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->requestAuthentication(DIGEST_AUTH); this->webServer->requestAuthentication(BASIC_AUTH);
return false; return false;
} }
@@ -158,8 +156,8 @@ protected:
// sensors page // sensors page
auto sensorsPage = (new StaticPage("/sensors.html", &LittleFS, F("/pages/sensors.html"), PORTAL_CACHE)) auto sensorsPage = (new StaticPage("/sensors.html", &LittleFS, F("/pages/sensors.html"), PORTAL_CACHE))
->setBeforeSendCallback([this]() { ->setBeforeSendCallback([this]() {
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->requestAuthentication(DIGEST_AUTH); this->webServer->requestAuthentication(BASIC_AUTH);
return false; return false;
} }
@@ -170,8 +168,8 @@ protected:
// upgrade page // upgrade page
auto upgradePage = (new StaticPage("/upgrade.html", &LittleFS, F("/pages/upgrade.html"), PORTAL_CACHE)) auto upgradePage = (new StaticPage("/upgrade.html", &LittleFS, F("/pages/upgrade.html"), PORTAL_CACHE))
->setBeforeSendCallback([this]() { ->setBeforeSendCallback([this]() {
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->requestAuthentication(DIGEST_AUTH); this->webServer->requestAuthentication(BASIC_AUTH);
return false; return false;
} }
@@ -181,7 +179,7 @@ protected:
// OTA // OTA
auto upgradeHandler = (new UpgradeHandler("/api/upgrade"))->setCanUploadCallback([this](const String& uri) { auto upgradeHandler = (new UpgradeHandler("/api/upgrade"))->setCanUploadCallback([this](const String& uri) {
if (this->isAuthRequired() && !this->webServer->authenticate(settings.portal.login, settings.portal.password)) { if (this->isAuthRequired() && !this->isValidCredentials()) {
this->webServer->sendHeader(F("Connection"), F("close")); this->webServer->sendHeader(F("Connection"), F("close"));
this->webServer->send(401); this->webServer->send(401);
return false; return false;
@@ -222,11 +220,9 @@ protected:
// backup // backup
this->webServer->on(F("/api/backup/save"), HTTP_GET, [this]() { this->webServer->on(F("/api/backup/save"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
JsonDocument doc; JsonDocument doc;
@@ -248,11 +244,9 @@ protected:
}); });
this->webServer->on(F("/api/backup/restore"), HTTP_POST, [this]() { this->webServer->on(F("/api/backup/restore"), HTTP_POST, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
if (vars.states.restarting) { if (vars.states.restarting) {
return this->webServer->send(503); return this->webServer->send(503);
@@ -329,11 +323,9 @@ protected:
// network // network
this->webServer->on(F("/api/network/settings"), HTTP_GET, [this]() { this->webServer->on(F("/api/network/settings"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
JsonDocument doc; JsonDocument doc;
networkSettingsToJson(networkSettings, doc); networkSettingsToJson(networkSettings, doc);
@@ -343,11 +335,9 @@ protected:
}); });
this->webServer->on(F("/api/network/settings"), HTTP_POST, [this]() { this->webServer->on(F("/api/network/settings"), HTTP_POST, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
if (vars.states.restarting) { if (vars.states.restarting) {
return this->webServer->send(503); return this->webServer->send(503);
@@ -402,11 +392,8 @@ protected:
}); });
this->webServer->on(F("/api/network/scan"), HTTP_GET, [this]() { this->webServer->on(F("/api/network/scan"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) { return this->webServer->send(401);
this->webServer->send(401);
return;
}
} }
auto apCount = WiFi.scanComplete(); auto apCount = WiFi.scanComplete();
@@ -448,11 +435,9 @@ protected:
// settings // settings
this->webServer->on(F("/api/settings"), HTTP_GET, [this]() { this->webServer->on(F("/api/settings"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
JsonDocument doc; JsonDocument doc;
settingsToJson(settings, doc); settingsToJson(settings, doc);
@@ -462,11 +447,9 @@ protected:
}); });
this->webServer->on(F("/api/settings"), HTTP_POST, [this]() { this->webServer->on(F("/api/settings"), HTTP_POST, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
if (vars.states.restarting) { if (vars.states.restarting) {
return this->webServer->send(503); return this->webServer->send(503);
@@ -513,11 +496,9 @@ protected:
// sensors list // sensors list
this->webServer->on(F("/api/sensors"), HTTP_GET, [this]() { this->webServer->on(F("/api/sensors"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
bool detailed = false; bool detailed = false;
if (this->webServer->hasArg(F("detailed"))) { if (this->webServer->hasArg(F("detailed"))) {
@@ -528,6 +509,7 @@ protected:
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) { for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
if (detailed) { if (detailed) {
auto& sSensor = Sensors::settings[sensorId]; auto& sSensor = Sensors::settings[sensorId];
doc[sensorId][FPSTR(S_ENABLED)] = sSensor.enabled;
doc[sensorId][FPSTR(S_NAME)] = sSensor.name; doc[sensorId][FPSTR(S_NAME)] = sSensor.name;
doc[sensorId][FPSTR(S_PURPOSE)] = static_cast<uint8_t>(sSensor.purpose); doc[sensorId][FPSTR(S_PURPOSE)] = static_cast<uint8_t>(sSensor.purpose);
sensorResultToJson(sensorId, doc[sensorId]); sensorResultToJson(sensorId, doc[sensorId]);
@@ -543,11 +525,9 @@ protected:
// sensor settings // sensor settings
this->webServer->on(F("/api/sensor"), HTTP_GET, [this]() { this->webServer->on(F("/api/sensor"), HTTP_GET, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
if (!this->webServer->hasArg(F("id"))) { if (!this->webServer->hasArg(F("id"))) {
return this->webServer->send(400); return this->webServer->send(400);
@@ -571,11 +551,9 @@ protected:
}); });
this->webServer->on(F("/api/sensor"), HTTP_POST, [this]() { this->webServer->on(F("/api/sensor"), HTTP_POST, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
if (vars.states.restarting) { if (vars.states.restarting) {
return this->webServer->send(503); return this->webServer->send(503);
@@ -654,11 +632,9 @@ protected:
}); });
this->webServer->on(F("/api/vars"), HTTP_POST, [this]() { this->webServer->on(F("/api/vars"), HTTP_POST, [this]() {
if (this->isAuthRequired()) { if (this->isAuthRequired() && !this->isValidCredentials()) {
if (!this->webServer->authenticate(settings.portal.login, settings.portal.password)) {
return this->webServer->send(401); return this->webServer->send(401);
} }
}
const String& plain = this->webServer->arg(0); const String& plain = this->webServer->arg(0);
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Request /api/vars %d bytes: %s"), plain.length(), plain.c_str()); Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Request /api/vars %d bytes: %s"), plain.length(), plain.c_str());
@@ -956,6 +932,10 @@ protected:
return !network->isApEnabled() && settings.portal.auth && strlen(settings.portal.password); return !network->isApEnabled() && settings.portal.auth && strlen(settings.portal.password);
} }
bool isValidCredentials() {
return this->webServer->authenticate(settings.portal.login, settings.portal.password);
}
void onCaptivePortal() { void onCaptivePortal() {
const String& uri = this->webServer->uri(); const String& uri = this->webServer->uri();

View File

@@ -561,7 +561,7 @@ protected:
return; return;
} }
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.01f); float rawTemp = (pChar->getValue<int16_t>() * 0.01f);
Log.straceln( Log.straceln(
FPSTR(L_SENSORS_BLE), FPSTR(L_SENSORS_BLE),
F("Sensor #%hhu '%s': received temp: %.2f"), F("Sensor #%hhu '%s': received temp: %.2f"),
@@ -634,7 +634,7 @@ protected:
return; return;
} }
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.1f); float rawTemp = (pChar->getValue<int16_t>() * 0.1f);
Log.straceln( Log.straceln(
FPSTR(L_SENSORS_BLE), FPSTR(L_SENSORS_BLE),
F("Sensor #%hhu '%s': received temp: %.2f"), F("Sensor #%hhu '%s': received temp: %.2f"),
@@ -719,7 +719,7 @@ protected:
return; return;
} }
float rawHumidity = ((pData[0] | (pData[1] << 8)) * 0.01f); float rawHumidity = (pChar->getValue<uint16_t>() * 0.01f);
Log.straceln( Log.straceln(
FPSTR(L_SENSORS_BLE), FPSTR(L_SENSORS_BLE),
F("Sensor #%hhu '%s': received humidity: %.2f"), F("Sensor #%hhu '%s': received humidity: %.2f"),
@@ -818,7 +818,7 @@ protected:
return; return;
} }
uint8_t rawBattery = pData[0]; auto rawBattery = pChar->getValue<uint8_t>();
Log.straceln( Log.straceln(
FPSTR(L_SENSORS_BLE), FPSTR(L_SENSORS_BLE),
F("Sensor #%hhu '%s': received battery: %.2f"), F("Sensor #%hhu '%s': received battery: %.2f"),

View File

@@ -380,13 +380,18 @@
console.log(newSettings); console.log(newSettings);
} }
let parameters = { cache: 'no-cache' }; let parameters = {
method: "GET",
cache: "no-cache",
credentials: "include"
};
if (modified) { if (modified) {
parameters.method = "POST"; parameters.method = "POST";
parameters.body = JSON.stringify(newSettings); parameters.body = JSON.stringify(newSettings);
} }
const response = await fetch('/api/settings', parameters); const response = await fetch("/api/settings", parameters);
if (!response.ok) { if (!response.ok) {
throw new Error('Response not valid'); throw new Error('Response not valid');
} }
@@ -424,7 +429,11 @@
// vars // vars
try { try {
const response = await fetch('/api/vars', { cache: 'no-cache' }); const response = await fetch("/api/vars", {
cache: "no-cache",
credentials: "include"
});
if (!response.ok) { if (!response.ok) {
throw new Error('Response not valid'); throw new Error('Response not valid');
} }
@@ -540,7 +549,11 @@
// sensors // sensors
try { try {
const response = await fetch("/api/sensors?detailed=1", { cache: "no-cache" }); const response = await fetch("/api/sensors?detailed=1", {
cache: "no-cache",
credentials: "include"
});
if (!response.ok) { if (!response.ok) {
throw new Error("Response not valid"); throw new Error("Response not valid");
} }
@@ -568,12 +581,12 @@
} }
const sData = result[sensorId]; const sData = result[sensorId];
if (sData.purpose == 255) { if (!sData.enabled || sData.purpose == 255) {
sensorNode.classList.add("hidden"); sensorNode.classList.toggle("hidden", true);
continue; continue;
} }
sensorNode.classList.remove("hidden"); sensorNode.classList.toggle("hidden", false);
setStatus( setStatus(
".sStatus", ".sStatus",

View File

@@ -170,7 +170,11 @@
setTimeout(async function onLoadPage() { setTimeout(async function onLoadPage() {
try { try {
const response = await fetch('/api/info', { cache: 'no-cache' }); const response = await fetch("/api/info", {
cache: "no-cache",
credentials: "include"
});
if (!response.ok) { if (!response.ok) {
throw new Error('Response not valid'); throw new Error('Response not valid');
} }

View File

@@ -199,7 +199,11 @@
}; };
try { try {
const response = await fetch('/api/network/settings', { cache: 'no-cache' }); const response = await fetch("/api/network/settings", {
cache: "no-cache",
credentials: "include"
});
if (!response.ok) { if (!response.ok) {
throw new Error('Response not valid'); throw new Error('Response not valid');
} }

View File

@@ -194,7 +194,11 @@
const templateNode = container.querySelector("#template"); const templateNode = container.querySelector("#template");
try { try {
const response = await fetch("/api/sensors", { cache: "no-cache" }); const response = await fetch("/api/sensors", {
cache: "no-cache",
credentials: "include"
});
if (!response.ok) { if (!response.ok) {
throw new Error("Response not valid"); throw new Error("Response not valid");
} }
@@ -287,7 +291,11 @@
} }
try { try {
const response = await fetch(sensorForm.action, { cache: "no-cache" }); const response = await fetch(sensorForm.action, {
cache: "no-cache",
credentials: "include"
});
if (response.status != 200) { if (response.status != 200) {
return; return;
} }

View File

@@ -808,7 +808,11 @@
}; };
try { try {
const response = await fetch('/api/settings', { cache: 'no-cache' }); const response = await fetch("/api/settings", {
cache: "no-cache",
credentials: "include"
});
if (!response.ok) { if (!response.ok) {
throw new Error('Response not valid'); throw new Error('Response not valid');
} }

View File

@@ -32,7 +32,7 @@ class Lang {
} }
if (!this.localeIsSupported(this.defaultLocale)) { if (!this.localeIsSupported(this.defaultLocale)) {
const selected = this.switcher.selectedIndex ?? 0; const selected = this.switcher.selectedIndex ? this.switcher.selectedIndex : 0;
this.defaultLocale = this.switcher.options[selected].value; this.defaultLocale = this.switcher.options[selected].value;
} }

View File

@@ -60,10 +60,11 @@ const setupForm = (formSelector, onResultCallback = null, noCastItems = []) => {
} }
let response = await fetch(url, { let response = await fetch(url, {
method: 'POST', method: "POST",
cache: 'no-cache', cache: "no-cache",
credentials: "include",
headers: { headers: {
'Content-Type': 'application/json' "Content-Type": "application/json"
}, },
body: form2json(fd, noCastItems) body: form2json(fd, noCastItems)
}); });
@@ -218,7 +219,10 @@ const setupNetworkScanForm = (formSelector, tableSelector) => {
attempts--; attempts--;
try { try {
let response = await fetch(url, { cache: 'no-cache' }); let response = await fetch(url, {
cache: "no-cache",
credentials: "include"
});
if (response.status == 200) { if (response.status == 200) {
await onSuccess(response); await onSuccess(response);
@@ -309,10 +313,11 @@ const setupRestoreBackupForm = (formSelector) => {
if (data.settings != undefined) { if (data.settings != undefined) {
let response = await fetch(url, { let response = await fetch(url, {
method: 'POST', method: "POST",
cache: 'no-cache', cache: "no-cache",
credentials: "include",
headers: { headers: {
'Content-Type': 'application/json' "Content-Type": "application/json"
}, },
body: JSON.stringify({"settings": data.settings}) body: JSON.stringify({"settings": data.settings})
}); });
@@ -331,10 +336,11 @@ const setupRestoreBackupForm = (formSelector) => {
payload["sensors"][sensorId] = data.sensors[sensorId]; payload["sensors"][sensorId] = data.sensors[sensorId];
const response = await fetch(url, { const response = await fetch(url, {
method: 'POST', method: "POST",
cache: 'no-cache', cache: "no-cache",
credentials: "include",
headers: { headers: {
'Content-Type': 'application/json' "Content-Type": "application/json"
}, },
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
@@ -348,10 +354,11 @@ const setupRestoreBackupForm = (formSelector) => {
if (data.network != undefined) { if (data.network != undefined) {
let response = await fetch(url, { let response = await fetch(url, {
method: 'POST', method: "POST",
cache: 'no-cache', cache: "no-cache",
credentials: "include",
headers: { headers: {
'Content-Type': 'application/json' "Content-Type": "application/json"
}, },
body: JSON.stringify({"network": data.network}) body: JSON.stringify({"network": data.network})
}); });
@@ -496,8 +503,9 @@ const setupUpgradeForm = (formSelector) => {
try { try {
let fd = new FormData(form); let fd = new FormData(form);
let response = await fetch(url, { let response = await fetch(url, {
method: 'POST', method: "POST",
cache: 'no-cache', cache: "no-cache",
credentials: "include",
body: fd body: fd
}); });