More work on webserver
This commit is contained in:
48
README
48
README
@@ -6,22 +6,16 @@ OBP Keypad 6/1
|
|||||||
- Configuration mode via long key press (>3 s) on DST
|
- Configuration mode via long key press (>3 s) on DST
|
||||||
- Deep sleep and reset can be activated from configuration mode
|
- Deep sleep and reset can be activated from configuration mode
|
||||||
- Configuration via web interface
|
- Configuration via web interface
|
||||||
|
- Firmware update via web interface
|
||||||
- Buzzer for key press feedback
|
- Buzzer for key press feedback
|
||||||
passive, allowing tones to be programmed via PWM
|
passive, allowing tones to be programmed via PWM
|
||||||
- I²C temperature/humidity sensor SHT31
|
- I²C temperature/humidity sensor SHT31
|
||||||
|
- Light sensor, e.g. for automatic LED dimming
|
||||||
|
|
||||||
Later options
|
Later options
|
||||||
- Brightness sensor, e.g. for automatic LED dimming
|
- Brightness sensor, e.g. for automatic LED dimming
|
||||||
Reassign pins?:
|
Reassign pins?:
|
||||||
I²C -> D0, D1 (GPIO 44, 43)
|
I²C -> D0, D1 (GPIO 44, 43)
|
||||||
Reorder LEDs: A0 to A5 for the 6 LEDs
|
|
||||||
A6 as analog input for sensor
|
|
||||||
A7 reserved
|
|
||||||
- Version 2
|
|
||||||
- Seatalk 1 connector for Raymarine tiller pilot remote control
|
|
||||||
- Version X, always optional
|
|
||||||
- 2.9" ePaper display to show key assignments
|
|
||||||
also means: much more complex enclosure
|
|
||||||
|
|
||||||
To prevent the LEDs from being distracting, switching is possible between
|
To prevent the LEDs from being distracting, switching is possible between
|
||||||
permanent illumination and only brief flashing on actuation:
|
permanent illumination and only brief flashing on actuation:
|
||||||
@@ -63,6 +57,9 @@ Connections
|
|||||||
To connect LED PCB
|
To connect LED PCB
|
||||||
JST 2.54 XH 7-pin connector -> LEDs + GND
|
JST 2.54 XH 7-pin connector -> LEDs + GND
|
||||||
|
|
||||||
|
To connect light sensor to LED PCB
|
||||||
|
2 pins for +3.3V and GPIO
|
||||||
|
|
||||||
For I²C modules
|
For I²C modules
|
||||||
2x 4pin-pin female headers
|
2x 4pin-pin female headers
|
||||||
qwiic-connector (JST_SH_BM04B-SRSS-TB_04x1.00mm)
|
qwiic-connector (JST_SH_BM04B-SRSS-TB_04x1.00mm)
|
||||||
@@ -83,10 +80,11 @@ Connections
|
|||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
|
|
||||||
With the currently used pre-wired buttons, the connection wires are
|
Do not use used pre-wired buttons, the connection wires are extremely
|
||||||
extremely delicate. Easy to break and poor workmanship.
|
delicate. Easy to break and poor workmanship.
|
||||||
Better to use buttons without cables. Solid wire with 0.25 mm² seems
|
Better to use buttons without cables. Solid wire with 0.25 mm² seems
|
||||||
best suited, both on the button side and for insertion into the terminal block.
|
best suited, both on the button side and for insertion into the terminal
|
||||||
|
block.
|
||||||
|
|
||||||
There are various variants with different spring forces.
|
There are various variants with different spring forces.
|
||||||
Final button selection still pending.
|
Final button selection still pending.
|
||||||
@@ -105,33 +103,7 @@ Do not use the 3.3 V pin. It is intended as an output!
|
|||||||
The mapping from Nano pins to GPIOs still needs to be verified.
|
The mapping from Nano pins to GPIOs still needs to be verified.
|
||||||
The Nano can be operated in two different mapping modes!
|
The Nano can be operated in two different mapping modes!
|
||||||
|
|
||||||
KEY Color Pin Remarks
|
The pin assignments are defined in main.h.
|
||||||
----- ------- -------- --------------------
|
|
||||||
1 B D2 GPIO5
|
|
||||||
2 B D3 GPIO6
|
|
||||||
3 B D4 GPIO7
|
|
||||||
4 B D5 GPIO8
|
|
||||||
5 B D6 GPIO9
|
|
||||||
6 Y D7 GPIO10
|
|
||||||
DST Y D8 GPIO17 Destination, configuration
|
|
||||||
|
|
||||||
LED Pin Remarks
|
|
||||||
------ ---------- ----------------------
|
|
||||||
A A0 GPIO1
|
|
||||||
B A1 GPIO2
|
|
||||||
C A2 GPIO3
|
|
||||||
RGB-R A3 GPIO4
|
|
||||||
RGB-G A6 GPIO13
|
|
||||||
RGB-B A7 GPIO14
|
|
||||||
|
|
||||||
CAN Pin Remarks
|
|
||||||
------ ---------- ----------------------
|
|
||||||
TX D9 GPIO18
|
|
||||||
RX D10 GPIO21
|
|
||||||
|
|
||||||
BUZZ Pin Remarks
|
|
||||||
------ ---------- ----------------------
|
|
||||||
TBD
|
|
||||||
|
|
||||||
Bill of materials (WIP)
|
Bill of materials (WIP)
|
||||||
-----------------
|
-----------------
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ static const ConfigDef configdefs[] = {
|
|||||||
{"systemMode", ConfigType::CHAR, 'K'},
|
{"systemMode", ConfigType::CHAR, 'K'},
|
||||||
{"nightMode", ConfigType::BOOL, false},
|
{"nightMode", ConfigType::BOOL, false},
|
||||||
{"logLevel", ConfigType::BYTE, uint8_t(4)},
|
{"logLevel", ConfigType::BYTE, uint8_t(4)},
|
||||||
{"adminPassword", ConfigType::STRING, String("obpkp61")},
|
{"adminPassword", ConfigType::STRING, String(ADMIN_PASS)},
|
||||||
{"useAdminPass", ConfigType::BOOL, true},
|
{"useAdminPass", ConfigType::BOOL, true},
|
||||||
{"instDesc1", ConfigType::STRING, String("")},
|
{"instDesc1", ConfigType::STRING, String("")},
|
||||||
{"instDesc2", ConfigType::STRING, String("")},
|
{"instDesc2", ConfigType::STRING, String("")},
|
||||||
{"apEnable", ConfigType::BOOL, true},
|
{"apEnable", ConfigType::BOOL, true},
|
||||||
{"apPassword", ConfigType::STRING, String("obpkp61")},
|
{"apPassword", ConfigType::STRING, String(WIFI_PASS)},
|
||||||
{"apIp", ConfigType::STRING, String("192.168.15.1")},
|
{"apIp", ConfigType::STRING, String("192.168.15.1")},
|
||||||
{"apMask", ConfigType::STRING, String("255.255.255.0")},
|
{"apMask", ConfigType::STRING, String("255.255.255.0")},
|
||||||
{"stopApTime", ConfigType::SHORT, int16_t(0)},
|
{"stopApTime", ConfigType::SHORT, int16_t(0)},
|
||||||
@@ -94,6 +94,7 @@ public:
|
|||||||
void loadValue(const char* key);
|
void loadValue(const char* key);
|
||||||
void save();
|
void save();
|
||||||
void dump();
|
void dump();
|
||||||
|
void clear();
|
||||||
|
|
||||||
bool hasKey(const char* key);
|
bool hasKey(const char* key);
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,9 @@
|
|||||||
|
|
||||||
#define PREF_NAME "nvs"
|
#define PREF_NAME "nvs"
|
||||||
|
|
||||||
|
// Generic
|
||||||
|
#define ADMIN_PASS "obpkp61"
|
||||||
|
|
||||||
// WIFI AP
|
// WIFI AP
|
||||||
#define WIFI_CHANNEL 9
|
#define WIFI_CHANNEL 9
|
||||||
#define WIFI_MAX_STA 2
|
#define WIFI_MAX_STA 2
|
||||||
|
|||||||
@@ -220,6 +220,13 @@ void Config::dump() {
|
|||||||
LOGI(TAG, "====================================");
|
LOGI(TAG, "====================================");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::clear() {
|
||||||
|
LOGI(TAG, "Clearing NVS volume: %s", PREF_NAME);
|
||||||
|
prefs.begin(PREF_NAME, false);
|
||||||
|
prefs.clear();
|
||||||
|
prefs.end();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Config::get(const char* key) const {
|
T Config::get(const char* key) const {
|
||||||
return std::get<T>(values.at(key));
|
return std::get<T>(values.at(key));
|
||||||
|
|||||||
@@ -623,16 +623,18 @@ void send_sensor_brightness(uint16_t value) {
|
|||||||
// device instance 8bits
|
// device instance 8bits
|
||||||
// brightness 0-100%, resolution 0.1% 16bits
|
// brightness 0-100%, resolution 0.1% 16bits
|
||||||
// 3 bytes reserved
|
// 3 bytes reserved
|
||||||
|
uint16_t n2kvalue = value * 1000UL / 4095; // 0..100%, resolution 0.1
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
N2kMsg.SetPGN(65280); // proprietary PGN
|
N2kMsg.SetPGN(65280); // proprietary PGN
|
||||||
N2kMsg.Priority = 6;
|
N2kMsg.Priority = 6;
|
||||||
// 11bits manuf.-code, 2bits reserved (1), 3bits industry group
|
// 11bits manuf.-code, 2bits reserved (1), 3bits industry group
|
||||||
N2kMsg.Add2ByteUInt((N2K_MANUFACTURERCODE & 0x7FF) | (0x03 << 11) | ((N2K_INDUSTRYGROUP & 0x7) << 13));
|
N2kMsg.Add2ByteUInt((N2K_MANUFACTURERCODE & 0x7FF) | (0x03 << 11) | ((N2K_INDUSTRYGROUP & 0x7) << 13));
|
||||||
N2kMsg.AddByte(0); // instance not yet used now
|
N2kMsg.AddByte(0); // instance not yet used now
|
||||||
N2kMsg.Add2ByteUInt(value * 1000UL / 4095); // resolution 0.1
|
N2kMsg.Add2ByteUInt(n2kvalue);
|
||||||
N2kMsg.AddByte(0xFF); //reserved bytes
|
N2kMsg.AddByte(0xFF); //reserved bytes
|
||||||
N2kMsg.AddByte(0xFF);
|
N2kMsg.AddByte(0xFF);
|
||||||
N2kMsg.AddByte(0xFF);
|
N2kMsg.AddByte(0xFF);
|
||||||
|
LOGI(TAG, "Sending LDR value=%d (%d)", n2kvalue, value);
|
||||||
NMEA2000.SendMsg(N2kMsg);
|
NMEA2000.SendMsg(N2kMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -772,10 +774,9 @@ void loop() {
|
|||||||
send_sensor_temphum(temp + 273.15, hum);
|
send_sensor_temphum(temp + 273.15, hum);
|
||||||
|
|
||||||
#ifdef HARDWARE_V2
|
#ifdef HARDWARE_V2
|
||||||
|
// Send brightness to NMEA2000 (proprietary)
|
||||||
int ldrval = analogRead(LDR);
|
int ldrval = analogRead(LDR);
|
||||||
LOGI(TAG, "LDR value =%d", ldrval);
|
send_sensor_brightness(ldrval);
|
||||||
// TODO send brightness to NMEA2000
|
|
||||||
//send_sensor_brightness(ldrval);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ String uptime_with_unit() {
|
|||||||
return String(uptime) + " " + uptime_unit;
|
return String(uptime) + " " + uptime_unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check_pass(String hash) {
|
||||||
|
if (! config.getBool("useAdminPass")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
char salt[9]; // use to easy get upper case hex
|
||||||
|
sprintf(salt, "%08X", apiToken + (millis()/1000UL & ~0x7UL));
|
||||||
|
String passhash = get_sha256(String(salt) + config.getString("adminPassword"));
|
||||||
|
LOGD(TAG, "check hash: %s", hash.c_str());
|
||||||
|
LOGD(TAG, "check against: %s", passhash.c_str());
|
||||||
|
return hash == passhash;
|
||||||
|
}
|
||||||
|
|
||||||
void webserver_init() {
|
void webserver_init() {
|
||||||
|
|
||||||
// Route for root / web page
|
// Route for root / web page
|
||||||
@@ -103,16 +115,23 @@ void webserver_init() {
|
|||||||
|
|
||||||
server.on("/api/checkpass", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/checkpass", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
// hash has to be in sha256 format
|
// hash has to be in sha256 format
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
LOGD(TAG, "checkpass called");
|
LOGD(TAG, "checkpass called");
|
||||||
String hash = request->arg("hash");
|
String hash = request->arg("hash");
|
||||||
StaticJsonDocument<100> doc;
|
//StaticJsonDocument<100> doc;
|
||||||
String passhash = get_sha256(config.getString("adminPassword"));
|
//char salt[9];
|
||||||
LOGD(TAG, "check hash: %s", hash.c_str());
|
//sprintf(salt, "%08X", apiToken + (millis()/1000UL & ~0x7UL));
|
||||||
LOGD(TAG, "check against: %s", passhash.c_str());
|
//String passhash = get_sha256(String(salt) + config.getString("adminPassword"));
|
||||||
doc["status"] = hash == passhash ? "OK" : "FAILED";
|
//LOGD(TAG, "check hash: %s", hash.c_str());
|
||||||
String out;
|
//LOGD(TAG, "check against: %s", passhash.c_str());
|
||||||
serializeJson(doc, out);
|
//doc["status"] = check_pass(hash) ? "OK" : "FAILED";
|
||||||
request->send(200, "application/json", out);
|
//String out;
|
||||||
|
//serializeJson(doc, out);
|
||||||
|
//request->send(200, "application/json", out);
|
||||||
|
response->print(R"({"status":)");
|
||||||
|
response->print(check_pass(hash) ? R"("OK")" : R"("FAILED")");
|
||||||
|
response->print("}");
|
||||||
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
@@ -125,12 +144,10 @@ void webserver_init() {
|
|||||||
doc["instDesc2"] = config.getString("instDesc2");
|
doc["instDesc2"] = config.getString("instDesc2");
|
||||||
doc["logLevel"] = loglevel;
|
doc["logLevel"] = loglevel;
|
||||||
doc["version"] = VERSION;
|
doc["version"] = VERSION;
|
||||||
doc["AdminPassword"] = "********";
|
|
||||||
doc["useAdminPass"] = config.getBool("useAdminPass") ? "true" : "false";
|
doc["useAdminPass"] = config.getBool("useAdminPass") ? "true" : "false";
|
||||||
doc["apEnable"] = config.getBool("apEnable") ? "true" : "false";
|
doc["apEnable"] = config.getBool("apEnable") ? "true" : "false";
|
||||||
doc["apIp"] = config.getString("apIp");
|
doc["apIp"] = config.getString("apIp");
|
||||||
doc["apMask"] = config.getString("apMask");
|
doc["apMask"] = config.getString("apMask");
|
||||||
doc["apPassword"] = "********";
|
|
||||||
doc["stopApTime"] = config.getShort("stopApTime");
|
doc["stopApTime"] = config.getShort("stopApTime");
|
||||||
doc["apHidden"] = config.getBool("apHidden") ? "true" : "false";
|
doc["apHidden"] = config.getBool("apHidden") ? "true" : "false";
|
||||||
doc["cpuSpeed"] = config.getShort("cpuSpeed");
|
doc["cpuSpeed"] = config.getShort("cpuSpeed");
|
||||||
@@ -160,31 +177,55 @@ void webserver_init() {
|
|||||||
doc["n2kDestC"] = config.getString("n2kDestC");
|
doc["n2kDestC"] = config.getString("n2kDestC");
|
||||||
doc["switchBankC"] = config.getByte("switchBankC");
|
doc["switchBankC"] = config.getByte("switchBankC");
|
||||||
doc["envInterval"] = config.getShort("envInterval");
|
doc["envInterval"] = config.getShort("envInterval");
|
||||||
|
|
||||||
|
// TODO needed? Perhaps because entry fields are created by this list
|
||||||
|
doc["AdminPassword"] = "********";
|
||||||
|
doc["apPassword"] = "********";
|
||||||
|
|
||||||
String out;
|
String out;
|
||||||
serializeJson(doc, out);
|
serializeJson(doc, out);
|
||||||
request->send(200, "application/json", out);
|
request->send(200, "application/json", out);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/api/reset", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/reset", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
String hash = request->arg("hash");
|
||||||
|
response->print(R"([{"status":)");
|
||||||
|
if (check_pass(hash)) {
|
||||||
LOGD(TAG, "reset called");
|
LOGD(TAG, "reset called");
|
||||||
StaticJsonDocument<100> doc;
|
response->print(R"("OK")");
|
||||||
doc["status"] = "OK";
|
response->print("}]");
|
||||||
String out;
|
|
||||||
serializeJson(doc, out);
|
|
||||||
request->send(200, "application/json", out);
|
|
||||||
ledcWrite(LEDC_RGBLED_B, 0); // blue config light off
|
ledcWrite(LEDC_RGBLED_B, 0); // blue config light off
|
||||||
led_blink(LEDC_RGBLED_G, 3, 4095, 500);
|
led_blink(LEDC_RGBLED_G, 3, 4095, 500);
|
||||||
esp_rom_uart_tx_wait_idle(0);
|
esp_rom_uart_tx_wait_idle(0);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
|
|
||||||
|
}
|
||||||
|
LOGD(TAG, "reset failed: wrong password");
|
||||||
|
response->print(R"("FAILED")");
|
||||||
|
response->print("}]");
|
||||||
|
|
||||||
|
/*StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "OK";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out); */
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/api/resetconfig", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/resetconfig", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
String hash = request->arg("hash");
|
||||||
|
if (check_pass(hash)) {
|
||||||
|
LOGD(TAG, "resetconfig: checkpass successful");
|
||||||
|
} else {
|
||||||
|
LOGD(TAG, "resetconfig: checkpass failed");
|
||||||
|
}
|
||||||
LOGD(TAG, "resetconfig called");
|
LOGD(TAG, "resetconfig called");
|
||||||
StaticJsonDocument<100> doc;
|
// config.clear();
|
||||||
doc["status"] = "FAILED";
|
response->print("{");
|
||||||
String out;
|
response->print(R"DELIM({"status": "FAILED"})DELIM");
|
||||||
serializeJson(doc, out);
|
response->print("}");
|
||||||
request->send(200, "application/json", out);
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request) {
|
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||||
@@ -229,6 +270,10 @@ void webserver_init() {
|
|||||||
sprintf(salt, "%08X", apiToken + (millis()/1000UL & ~0x7UL));
|
sprintf(salt, "%08X", apiToken + (millis()/1000UL & ~0x7UL));
|
||||||
doc["salt"] = salt;
|
doc["salt"] = salt;
|
||||||
|
|
||||||
|
// security warnings
|
||||||
|
doc["warnAdminPass"] = config.getString("AdminPassword") == ADMIN_PASS ? "true" : "false";
|
||||||
|
doc["warnApPass"] = config.getString("apPassword") == WIFI_PASS ? "true" : "false";
|
||||||
|
|
||||||
doc["status"] = "OK";
|
doc["status"] = "OK";
|
||||||
String out;
|
String out;
|
||||||
serializeJson(doc, out);
|
serializeJson(doc, out);
|
||||||
|
|||||||
@@ -44,15 +44,6 @@
|
|||||||
"description": "Log level at the USB port.\nHigher level means more output.",
|
"description": "Log level at the USB port.\nHigher level means more output.",
|
||||||
"category": "System"
|
"category": "System"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "adminPassword",
|
|
||||||
"label": "Admin Password",
|
|
||||||
"type": "password",
|
|
||||||
"default": "esp32admin",
|
|
||||||
"check": "checkAdminPass",
|
|
||||||
"description": "Set the password for configuration modifications and firmware upload",
|
|
||||||
"category": "System"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "useAdminPass",
|
"name": "useAdminPass",
|
||||||
"label": "Use Admin-Pass",
|
"label": "Use Admin-Pass",
|
||||||
@@ -61,6 +52,18 @@
|
|||||||
"description": "A password for configuration modifications is required.",
|
"description": "A password for configuration modifications is required.",
|
||||||
"category": "System"
|
"category": "System"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "adminPassword",
|
||||||
|
"label": "Admin Password",
|
||||||
|
"type": "password",
|
||||||
|
"default": "esp32admin",
|
||||||
|
"check": "checkAdminPass",
|
||||||
|
"description": "Set the password for configuration modifications and firmware upload",
|
||||||
|
"category": "System",
|
||||||
|
"condition": {
|
||||||
|
"useAdminPass": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "instDesc1",
|
"name": "instDesc1",
|
||||||
"label": "Description 1",
|
"label": "Description 1",
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ if (!window.isSecureContext) {
|
|||||||
|
|
||||||
<div id="statusPage" class="tabPage">
|
<div id="statusPage" class="tabPage">
|
||||||
<div id="statusPageContent">
|
<div id="statusPageContent">
|
||||||
|
<div class="row hidden">
|
||||||
|
<span class="value" id="warnAdminPass">OK</span>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="label">Firmware</span>
|
<span class="label">Firmware</span>
|
||||||
<span class="value" id="version">---</span>
|
<span class="value" id="version">---</span>
|
||||||
|
|||||||
@@ -68,10 +68,11 @@
|
|||||||
}
|
}
|
||||||
function update() {
|
function update() {
|
||||||
let now = (new Date()).getTime();
|
let now = (new Date()).getTime();
|
||||||
|
let is_connected = (lastUpdate + 3 * updateInterval) > now;
|
||||||
let ce = document.getElementById('connected');
|
let ce = document.getElementById('connected');
|
||||||
let cl = document.getElementById('conn_label');
|
let cl = document.getElementById('conn_label');
|
||||||
if (ce) {
|
if (ce) {
|
||||||
if ((lastUpdate + 3 * updateInterval) > now) {
|
if (is_connected) {
|
||||||
ce.classList.add('ok');
|
ce.classList.add('ok');
|
||||||
cl.textContent = 'connected';
|
cl.textContent = 'connected';
|
||||||
}
|
}
|
||||||
@@ -108,6 +109,7 @@
|
|||||||
resetForm();
|
resetForm();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
if (is_connected) {
|
||||||
// check if any dynamic list needs update
|
// check if any dynamic list needs update
|
||||||
for (let l in dynLists) {
|
for (let l in dynLists) {
|
||||||
if (loadDynList(l)) {
|
if (loadDynList(l)) {
|
||||||
@@ -115,6 +117,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function resetForm(ev) {
|
function resetForm(ev) {
|
||||||
getJson(apiPrefix + "/api/config")
|
getJson(apiPrefix + "/api/config")
|
||||||
.then(function (jsonData) {
|
.then(function (jsonData) {
|
||||||
@@ -942,6 +945,7 @@
|
|||||||
forEl('#adminPassInput', function (el) {
|
forEl('#adminPassInput', function (el) {
|
||||||
el.value = '';
|
el.value = '';
|
||||||
});
|
});
|
||||||
|
alert("Admin password not cached anymore.");
|
||||||
}
|
}
|
||||||
function ensurePass() {
|
function ensurePass() {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
|
|||||||
Reference in New Issue
Block a user