Consolidate the UI (#1537)

This commit is contained in:
Darrell 2025-02-10 19:54:40 -05:00 committed by GitHub
parent 69c3818653
commit 5ad56da68c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 5815 additions and 3629 deletions

View File

@ -20,6 +20,7 @@ build_flags =
-fipa-pta
-fno-exceptions
-flto=auto
-fpermissive
-Wall
-Wextra
-Wformat=2
@ -49,11 +50,10 @@ build_unflags =
-fexceptions
-fno-lto
framework = arduino
lib_ignore = AsyncTCP
lib_deps =
https://github.com/esphome/AsyncTCP.git#v2.0.1
https://github.com/esphome/ESPAsyncWebServer.git#v3.1.0
https://github.com/ESPresense/AsyncWiFiSettings.git#1.0.10
ESP32Async/AsyncTCP
ESP32Async/ESPAsyncWebServer
https://github.com/ESPresense/HeadlessWiFiSettings.git#v1.1.7
https://github.com/ESPresense/NimBLE-Arduino.git
marvinroger/AsyncMqttClient@^0.9.0
bblanchon/ArduinoJson@^6.21.3

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "string_utils.h"
#include <Adafruit_AHTX0.h>
@ -41,8 +41,8 @@ namespace AHTX0
void ConnectToWifi()
{
AHTX0_I2c_Bus = AsyncWiFiSettings.integer("AHTX0_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
AHTX0_I2c = AsyncWiFiSettings.string("AHTX0_I2c", "", "I2C address (0x38 or 0x39)");
AHTX0_I2c_Bus = HeadlessWiFiSettings.integer("AHTX0_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
AHTX0_I2c = HeadlessWiFiSettings.string("AHTX0_I2c", "", "I2C address (0x38 or 0x39)");
}
void SerialReport()

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <AsyncMqttClient.h>
#include "string_utils.h"
@ -74,8 +74,8 @@ namespace BH1750
void ConnectToWifi()
{
BH1750_I2c_Bus = AsyncWiFiSettings.integer("BH1750_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BH1750_I2c = AsyncWiFiSettings.string("BH1750_I2c", "", "I2C address (0x23 or 0x5C)");
BH1750_I2c_Bus = HeadlessWiFiSettings.integer("BH1750_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BH1750_I2c = HeadlessWiFiSettings.string("BH1750_I2c", "", "I2C address (0x23 or 0x5C)");
}
void SerialReport()

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "string_utils.h"
#include <Adafruit_BME280.h>
@ -52,8 +52,8 @@ namespace BME280
void ConnectToWifi()
{
BME280_I2c_Bus = AsyncWiFiSettings.integer("BME280_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BME280_I2c = AsyncWiFiSettings.string("BME280_I2c", "", "I2C address (0x76 or 0x77)");
BME280_I2c_Bus = HeadlessWiFiSettings.integer("BME280_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BME280_I2c = HeadlessWiFiSettings.string("BME280_I2c", "", "I2C address (0x76 or 0x77)");
}
void SerialReport()

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "string_utils.h"
#include <Adafruit_BMP085.h>
@ -39,8 +39,8 @@ namespace BMP180
void ConnectToWifi()
{
BMP180_I2c_Bus = AsyncWiFiSettings.integer("BMP180_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BMP180_I2c = AsyncWiFiSettings.string("BMP180_I2c", "", "I2C address (0x77)");
BMP180_I2c_Bus = HeadlessWiFiSettings.integer("BMP180_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BMP180_I2c = HeadlessWiFiSettings.string("BMP180_I2c", "", "I2C address (0x77)");
}
void SerialReport()

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "string_utils.h"
#include <Adafruit_BMP280.h>
@ -48,8 +48,8 @@ namespace BMP280
void ConnectToWifi()
{
BMP280_I2c_Bus = AsyncWiFiSettings.integer("BMP280_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BMP280_I2c = AsyncWiFiSettings.string("BMP280_I2c", "", "I2C address (0x76 or 0x77)");
BMP280_I2c_Bus = HeadlessWiFiSettings.integer("BMP280_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
BMP280_I2c = HeadlessWiFiSettings.string("BMP280_I2c", "", "I2C address (0x76 or 0x77)");
}
void SerialReport()

View File

@ -3,7 +3,7 @@
#include "defaults.h"
#include <Arduino.h>
#include <sstream>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
namespace BleFingerprintCollection {
// Public (externed)
@ -152,28 +152,28 @@ bool Config(String &id, String &json) {
}
void ConnectToWifi() {
knownMacs = AsyncWiFiSettings.string("known_macs", DEFAULT_KNOWN_MACS, "Known BLE mac addresses (no colons, space seperated)");
knownIrks = AsyncWiFiSettings.string("known_irks", DEFAULT_KNOWN_IRKS, "Known BLE identity resolving keys, should be 32 hex chars space seperated");
knownMacs = HeadlessWiFiSettings.string("known_macs", DEFAULT_KNOWN_MACS, "Known BLE mac addresses (no colons, space seperated)");
knownIrks = HeadlessWiFiSettings.string("known_irks", DEFAULT_KNOWN_IRKS, "Known BLE identity resolving keys, should be 32 hex chars space seperated");
query = AsyncWiFiSettings.string("query", DEFAULT_QUERY, "Query device ids for characteristics (eg. flora:)");
requeryMs = AsyncWiFiSettings.integer("requery_ms", 30, 3600, DEFAULT_REQUERY_MS / 1000, "Requery interval in seconds") * 1000;
query = HeadlessWiFiSettings.string("query", DEFAULT_QUERY, "Query device ids for characteristics (eg. flora:)");
requeryMs = HeadlessWiFiSettings.integer("requery_ms", 30, 3600, DEFAULT_REQUERY_MS / 1000, "Requery interval in seconds") * 1000;
countIds = AsyncWiFiSettings.string("count_ids", DEFAULT_COUNT_IDS, "Include id prefixes (space seperated)");
countEnter = AsyncWiFiSettings.floating("count_enter", 0, 100, DEFAULT_COUNT_ENTER, "Start counting devices less than distance (in meters)");
countExit = AsyncWiFiSettings.floating("count_exit", 0, 100, DEFAULT_COUNT_EXIT, "Stop counting devices greater than distance (in meters)");
countMs = AsyncWiFiSettings.integer("count_ms", 0, 3000000, DEFAULT_COUNT_MS, "Include devices with age less than (in ms)");
countIds = HeadlessWiFiSettings.string("count_ids", DEFAULT_COUNT_IDS, "Include id prefixes (space seperated)");
countEnter = HeadlessWiFiSettings.floating("count_enter", 0, 100, DEFAULT_COUNT_ENTER, "Start counting devices less than distance (in meters)");
countExit = HeadlessWiFiSettings.floating("count_exit", 0, 100, DEFAULT_COUNT_EXIT, "Stop counting devices greater than distance (in meters)");
countMs = HeadlessWiFiSettings.integer("count_ms", 0, 3000000, DEFAULT_COUNT_MS, "Include devices with age less than (in ms)");
include = AsyncWiFiSettings.string("include", DEFAULT_INCLUDE, "Include only sending these ids to mqtt (eg. apple:iphone10-6 apple:iphone13-2)");
exclude = AsyncWiFiSettings.string("exclude", DEFAULT_EXCLUDE, "Exclude sending these ids to mqtt (eg. exp:20 apple:iphone10-6)");
maxDistance = AsyncWiFiSettings.floating("max_dist", 0, 100, DEFAULT_MAX_DISTANCE, "Maximum distance to report (in meters)");
skipDistance = AsyncWiFiSettings.floating("skip_dist", 0, 10, DEFAULT_SKIP_DISTANCE, "Report early if beacon has moved more than this distance (in meters)");
skipMs = AsyncWiFiSettings.integer("skip_ms", 0, 3000000, DEFAULT_SKIP_MS, "Skip reporting if message age is less that this (in milliseconds)");
include = HeadlessWiFiSettings.string("include", DEFAULT_INCLUDE, "Include only sending these ids to mqtt (eg. apple:iphone10-6 apple:iphone13-2)");
exclude = HeadlessWiFiSettings.string("exclude", DEFAULT_EXCLUDE, "Exclude sending these ids to mqtt (eg. exp:20 apple:iphone10-6)");
maxDistance = HeadlessWiFiSettings.floating("max_dist", 0, 100, DEFAULT_MAX_DISTANCE, "Maximum distance to report (in meters)");
skipDistance = HeadlessWiFiSettings.floating("skip_dist", 0, 10, DEFAULT_SKIP_DISTANCE, "Report early if beacon has moved more than this distance (in meters)");
skipMs = HeadlessWiFiSettings.integer("skip_ms", 0, 3000000, DEFAULT_SKIP_MS, "Skip reporting if message age is less that this (in milliseconds)");
rxRefRssi = AsyncWiFiSettings.integer("ref_rssi", -100, 100, DEFAULT_RX_REF_RSSI, "Rssi expected from a 0dBm transmitter at 1 meter (NOT used for iBeacons or Eddystone)");
rxAdjRssi = AsyncWiFiSettings.integer("rx_adj_rssi", -100, 100, DEFAULT_RX_ADJ_RSSI, "Rssi adjustment for receiver (use only if you know this device has a weak antenna)");
absorption = AsyncWiFiSettings.floating("absorption", -100, 100, DEFAULT_ABSORPTION, "Factor used to account for absorption, reflection, or diffraction");
forgetMs = AsyncWiFiSettings.integer("forget_ms", 0, 3000000, DEFAULT_FORGET_MS, "Forget beacon if not seen for (in milliseconds)");
txRefRssi = AsyncWiFiSettings.integer("tx_ref_rssi", -100, 100, DEFAULT_TX_REF_RSSI, "Rssi expected from this tx power at 1m (used for node iBeacon)");
rxRefRssi = HeadlessWiFiSettings.integer("ref_rssi", -100, 100, DEFAULT_RX_REF_RSSI, "Rssi expected from a 0dBm transmitter at 1 meter (NOT used for iBeacons or Eddystone)");
rxAdjRssi = HeadlessWiFiSettings.integer("rx_adj_rssi", -100, 100, DEFAULT_RX_ADJ_RSSI, "Rssi adjustment for receiver (use only if you know this device has a weak antenna)");
absorption = HeadlessWiFiSettings.floating("absorption", -100, 100, DEFAULT_ABSORPTION, "Factor used to account for absorption, reflection, or diffraction");
forgetMs = HeadlessWiFiSettings.integer("forget_ms", 0, 3000000, DEFAULT_FORGET_MS, "Forget beacon if not seen for (in milliseconds)");
txRefRssi = HeadlessWiFiSettings.integer("tx_ref_rssi", -100, 100, DEFAULT_TX_REF_RSSI, "Rssi expected from this tx power at 1m (used for node iBeacon)");
std::istringstream iss(knownIrks.c_str());
std::string irk_hex;

View File

@ -1,7 +1,7 @@
#include "Button.h"
#include <AsyncMqttClient.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "GUI.h"
#include "defaults.h"
@ -31,14 +31,14 @@ void Setup() {
void ConnectToWifi() {
std::vector<String> pinTypes = {"Pullup", "Pullup Inverted", "Pulldown", "Pulldown Inverted", "Floating", "Floating Inverted"};
button_1Type = AsyncWiFiSettings.dropdown("button_1_type", pinTypes, 0, "Button One pin type");
button_1Pin = AsyncWiFiSettings.integer("button_1_pin", -1, "Button One pin (-1 for disable)");
button_1Timeout = AsyncWiFiSettings.floating("button_1_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Button One timeout (in seconds)");
button_1Type = HeadlessWiFiSettings.dropdown("button_1_type", pinTypes, 0, "Button One pin type");
button_1Pin = HeadlessWiFiSettings.integer("button_1_pin", -1, "Button One pin (-1 for disable)");
button_1Timeout = HeadlessWiFiSettings.floating("button_1_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Button One timeout (in seconds)");
button_1Detected = button_1Type & 0x01 ? LOW : HIGH;
button_2Type = AsyncWiFiSettings.dropdown("button_2_type", pinTypes, 0, "Button Two pin type");
button_2Pin = AsyncWiFiSettings.integer("button_2_pin", -1, "Button Two pin (-1 for disable)");
button_2Timeout = AsyncWiFiSettings.floating("button_2_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Button Two timeout (in seconds)");
button_2Type = HeadlessWiFiSettings.dropdown("button_2_type", pinTypes, 0, "Button Two pin type");
button_2Pin = HeadlessWiFiSettings.integer("button_2_pin", -1, "Button Two pin (-1 for disable)");
button_2Timeout = HeadlessWiFiSettings.floating("button_2_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Button Two timeout (in seconds)");
button_2Detected = button_2Type & 0x01 ? LOW : HIGH;
}

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <AsyncMqttClient.h>
#include "string_utils.h"
@ -106,9 +106,9 @@ namespace DHT
void ConnectToWifi()
{
dht11Pin = AsyncWiFiSettings.integer("dht11_pin", -1, "DHT11 sensor pin (-1 for disable)");
dht22Pin = AsyncWiFiSettings.integer("dht22_pin", -1, "DHT22 sensor pin (-1 for disable)");
dhtTempOffset = AsyncWiFiSettings.floating("dhtTemp_offset", -40, 125, 0.0, "DHT temperature offset");
dht11Pin = HeadlessWiFiSettings.integer("dht11_pin", -1, "DHT11 sensor pin (-1 for disable)");
dht22Pin = HeadlessWiFiSettings.integer("dht22_pin", -1, "DHT22 sensor pin (-1 for disable)");
dhtTempOffset = HeadlessWiFiSettings.floating("dhtTemp_offset", -40, 125, 0.0, "DHT temperature offset");
}
void SerialReport()

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <AsyncMqttClient.h>
#include "string_utils.h"
@ -108,8 +108,8 @@ namespace DS18B20
void ConnectToWifi()
{
ds18b20Pin = AsyncWiFiSettings.integer("ds18b20_pin", -1, "DS18B20 sensor pin (-1 for disable)");
dsTempOffset = AsyncWiFiSettings.floating("dsTemp_offset", -40, 125, 0.0, "DS18B20 temperature offset");
ds18b20Pin = HeadlessWiFiSettings.integer("ds18b20_pin", -1, "DS18B20 sensor pin (-1 for disable)");
dsTempOffset = HeadlessWiFiSettings.floating("dsTemp_offset", -40, 125, 0.0, "DS18B20 temperature offset");
}
void SerialReport()

View File

@ -4,7 +4,7 @@
#include "globals.h"
#include "mqtt.h"
#include "defaults.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <AsyncMqttClient.h>
#include "string_utils.h"
@ -26,8 +26,8 @@ namespace HX711
void ConnectToWifi()
{
sckPin = AsyncWiFiSettings.integer("HX711_sckPin", 0, "HX711 SCK (Clock) pin");
doutPin = AsyncWiFiSettings.integer("HX711_doutPin", 0, "HX711 DOUT (Data) pin");
sckPin = HeadlessWiFiSettings.integer("HX711_sckPin", 0, "HX711 SCK (Clock) pin");
doutPin = HeadlessWiFiSettings.integer("HX711_doutPin", 0, "HX711 DOUT (Data) pin");
}
void SerialReport()

View File

@ -134,6 +134,11 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
}
}
void onRestart(AsyncWebServerRequest *request) {
request->send(200, "text/plain", "Restarting...");
ESP.restart();
}
void Init(AsyncWebServer *server) {
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Origin"), "*");
DefaultHeaders::Instance().addHeader(F("Access-Control-Allow-Methods"), "*");
@ -146,12 +151,10 @@ void Init(AsyncWebServer *server) {
});
setupRoutes(server); // from ui_routes.h
server->on("/ui", HTTP_GET, [](AsyncWebServerRequest *request) {
request->redirect("/ui/");
});
server->on("/restart", HTTP_POST, onRestart);
server->on("/json", HTTP_GET, serveJson);
// Handle DELETE method for configs
server->on("/json/configs", HTTP_DELETE, [](AsyncWebServerRequest *request) {
if (!request->hasParam("id")) {
request->send(400, "application/json", F("{\"error\":\"Missing required parameter: id\"}"));

View File

@ -3,7 +3,7 @@
#include "I2C.h"
#include <Adafruit_BME280.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "defaults.h"
#include "globals.h"
@ -18,15 +18,14 @@ int I2C_Bus_2_SDA = 0;
int I2C_Bus_2_SCL = 0;
void ConnectToWifi() {
AsyncWiFiSettings.heading("<a href='https://espresense.com/configuration/settings#i2c-settings' target='_blank'>I2C Settings</a>", false);
I2C_Bus_1_SDA = AsyncWiFiSettings.integer("I2C_Bus_1_SDA", -1, 39, DEFAULT_I2C_BUS_1_SDA, "SDA pin (-1 to disable)");
I2C_Bus_1_SCL = AsyncWiFiSettings.integer("I2C_Bus_1_SCL", -1, 39, DEFAULT_I2C_BUS_1_SCL, "SCL pin (-1 to disable)");
I2C_Bus_1_SDA = HeadlessWiFiSettings.integer("I2C_Bus_1_SDA", -1, 39, DEFAULT_I2C_BUS_1_SDA, "SDA pin (-1 to disable)");
I2C_Bus_1_SCL = HeadlessWiFiSettings.integer("I2C_Bus_1_SCL", -1, 39, DEFAULT_I2C_BUS_1_SCL, "SCL pin (-1 to disable)");
I2C_Bus_2_SDA = AsyncWiFiSettings.integer("I2C_Bus_2_SDA", -1, 39, DEFAULT_I2C_BUS_2_SDA, "SDA pin (-1 to disable)");
I2C_Bus_2_SCL = AsyncWiFiSettings.integer("I2C_Bus_2_SCL", -1, 39, DEFAULT_I2C_BUS_2_SCL, "SCL pin (-1 to disable)");
I2C_Bus_2_SDA = HeadlessWiFiSettings.integer("I2C_Bus_2_SDA", -1, 39, DEFAULT_I2C_BUS_2_SDA, "SDA pin (-1 to disable)");
I2C_Bus_2_SCL = HeadlessWiFiSettings.integer("I2C_Bus_2_SCL", -1, 39, DEFAULT_I2C_BUS_2_SCL, "SCL pin (-1 to disable)");
I2CDebug = AsyncWiFiSettings.checkbox("I2CDebug", false, "Debug I2C addreses. Look at the serial log to get the correct address");
I2CDebug = HeadlessWiFiSettings.checkbox("I2CDebug", false, "Debug I2C addreses. Look at the serial log to get the correct address");
if (I2C_Bus_1_SDA != -1 && I2C_Bus_1_SDA != -1) {
I2C_Bus_1_Started = Wire.begin(I2C_Bus_1_SDA, I2C_Bus_1_SCL);

View File

@ -1,7 +1,7 @@
#include "LEDs.h"
#include <AsyncMqttClient.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <WS2812FX.h>
#include "Motion.h"
@ -34,22 +34,20 @@ void ConnectToWifi() {
std::vector<String> ledTypes = {"PWM", "PWM Inverted", "Addressable GRB", "Addressable GRBW", "Addressable RGB", "Addressable RGBW"};
std::vector<String> ledControlTypes = {"MQTT", "Status", "Motion", "Count"};
AsyncWiFiSettings.heading("<a href='https://espresense.com/configuration/settings#leds' target='_blank'>LEDs</a>", false);
led_1_type = HeadlessWiFiSettings.dropdown("led_1_type", ledTypes, DEFAULT_LED1_TYPE, "LED Type");
led_1_pin = HeadlessWiFiSettings.integer("led_1_pin", -1, 39, DEFAULT_LED1_PIN, "Pin (-1 to disable)");
led_1_cnt = HeadlessWiFiSettings.integer("led_1_cnt", -1, 39, DEFAULT_LED1_CNT, "Count (only applies to Addressable LEDs)");
led_1_cntrl = (ControlType)HeadlessWiFiSettings.dropdown("led_1_cntrl", ledControlTypes, DEFAULT_LED1_CNTRL, "LED Control");
led_1_type = AsyncWiFiSettings.dropdown("led_1_type", ledTypes, DEFAULT_LED1_TYPE, "LED Type");
led_1_pin = AsyncWiFiSettings.integer("led_1_pin", -1, 39, DEFAULT_LED1_PIN, "Pin (-1 to disable)");
led_1_cnt = AsyncWiFiSettings.integer("led_1_cnt", -1, 39, DEFAULT_LED1_CNT, "Count (only applies to Addressable LEDs)");
led_1_cntrl = (ControlType)AsyncWiFiSettings.dropdown("led_1_cntrl", ledControlTypes, DEFAULT_LED1_CNTRL, "LED Control");
led_2_type = HeadlessWiFiSettings.dropdown("led_2_type", ledTypes, 0, "LED Type");
led_2_pin = HeadlessWiFiSettings.integer("led_2_pin", -1, 39, -1, "Pin (-1 to disable)");
led_2_cnt = HeadlessWiFiSettings.integer("led_2_cnt", -1, 39, 1, "Count (only applies to Addressable LEDs)");
led_2_cntrl = (ControlType)HeadlessWiFiSettings.dropdown("led_2_cntrl", ledControlTypes, 0, "LED Control");
led_2_type = AsyncWiFiSettings.dropdown("led_2_type", ledTypes, 0, "LED Type");
led_2_pin = AsyncWiFiSettings.integer("led_2_pin", -1, 39, -1, "Pin (-1 to disable)");
led_2_cnt = AsyncWiFiSettings.integer("led_2_cnt", -1, 39, 1, "Count (only applies to Addressable LEDs)");
led_2_cntrl = (ControlType)AsyncWiFiSettings.dropdown("led_2_cntrl", ledControlTypes, 0, "LED Control");
led_3_type = AsyncWiFiSettings.dropdown("led_3_type", ledTypes, 0, "LED Type");
led_3_pin = AsyncWiFiSettings.integer("led_3_pin", -1, 39, -1, "Pin (-1 to disable)");
led_3_cnt = AsyncWiFiSettings.integer("led_3_cnt", -1, 39, 1, "Count (only applies to Addressable LEDs)");
led_3_cntrl = (ControlType)AsyncWiFiSettings.dropdown("led_3_cntrl", ledControlTypes, 0, "LED Control");
led_3_type = HeadlessWiFiSettings.dropdown("led_3_type", ledTypes, 0, "LED Type");
led_3_pin = HeadlessWiFiSettings.integer("led_3_pin", -1, 39, -1, "Pin (-1 to disable)");
led_3_cnt = HeadlessWiFiSettings.integer("led_3_cnt", -1, 39, 1, "Count (only applies to Addressable LEDs)");
led_3_cntrl = (ControlType)HeadlessWiFiSettings.dropdown("led_3_cntrl", ledControlTypes, 0, "LED Control");
leds.push_back(newLed(1, led_1_cntrl, led_1_type, led_1_pin, led_1_cnt));
leds.push_back(newLed(2, led_2_cntrl, led_2_type, led_2_pin, led_2_cnt));

View File

@ -1,7 +1,7 @@
#pragma once
#include <ArduinoJson.h>
#include <AsyncMqttClient.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "BleFingerprint.h"
#include <NimBLEClient.h>
#include <NimBLEDevice.h>

View File

@ -1,7 +1,7 @@
#include "Motion.h"
#include <AsyncMqttClient.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "GUI.h"
#include "defaults.h"
@ -31,14 +31,14 @@ void Setup() {
void ConnectToWifi() {
std::vector<String> pinTypes = {"Pullup", "Pullup Inverted", "Pulldown", "Pulldown Inverted", "Floating", "Floating Inverted"};
pirType = AsyncWiFiSettings.dropdown("pir_type", pinTypes, 0, "PIR motion pin type");
pirPin = AsyncWiFiSettings.integer("pir_pin", -1, "PIR motion pin (-1 for disable)");
pirTimeout = AsyncWiFiSettings.floating("pir_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "PIR motion timeout (in seconds)");
pirType = HeadlessWiFiSettings.dropdown("pir_type", pinTypes, 0, "PIR motion pin type");
pirPin = HeadlessWiFiSettings.integer("pir_pin", -1, "PIR motion pin (-1 for disable)");
pirTimeout = HeadlessWiFiSettings.floating("pir_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "PIR motion timeout (in seconds)");
pirDetected = pirType & 0x01 ? LOW : HIGH;
radarType = AsyncWiFiSettings.dropdown("radar_type", pinTypes, 0, "Radar motion pin type");
radarPin = AsyncWiFiSettings.integer("radar_pin", -1, "Radar motion pin (-1 for disable)");
radarTimeout = AsyncWiFiSettings.floating("radar_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Radar motion timeout (in seconds)");
radarType = HeadlessWiFiSettings.dropdown("radar_type", pinTypes, 0, "Radar motion pin type");
radarPin = HeadlessWiFiSettings.integer("radar_pin", -1, "Radar motion pin (-1 for disable)");
radarTimeout = HeadlessWiFiSettings.floating("radar_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Radar motion timeout (in seconds)");
radarDetected = radarType & 0x01 ? LOW : HIGH;
}

View File

@ -5,7 +5,7 @@
#include <sstream>
#include <AsyncMqttClient.h>
#include "BleFingerprint.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
namespace NameModelHandler {

View File

@ -1,7 +1,7 @@
#ifdef SENSORS
#include "SHT.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <SHTSensor.h>
#include "defaults.h"
@ -30,7 +30,7 @@ void Setup() {
}
void ConnectToWifi() {
bus = AsyncWiFiSettings.integer("SHT_I2c_Bus", 1, 2, -1, "I2C Bus (-1 to disable)");
bus = HeadlessWiFiSettings.integer("SHT_I2c_Bus", 1, 2, -1, "I2C Bus (-1 to disable)");
}
void SerialReport() {

View File

@ -1,7 +1,7 @@
#ifdef SENSORS
#include "SensirionSGP30.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <SparkFun_SGP30_Arduino_Library.h>
#include "defaults.h"
@ -41,8 +41,8 @@ void Setup() {
}
void ConnectToWifi() {
SGP30_I2c_Bus = AsyncWiFiSettings.integer("SGP30_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
SGP30_I2c = AsyncWiFiSettings.string("SGP30_I2c", "", "I2C address (0x58)");
SGP30_I2c_Bus = HeadlessWiFiSettings.integer("SGP30_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
SGP30_I2c = HeadlessWiFiSettings.string("SGP30_I2c", "", "I2C address (0x58)");
}
void SerialReport() {
@ -62,17 +62,17 @@ void Loop() {
sgp->measureAirQuality();
float co2 = sgp->CO2;
float tvoc = sgp->TVOC;
if (SGP30PreviousSensorMillis > 30000) { // First 30 seconds after boot, don't report
if (SGP30PreviousReportMillis == 0 || millis() - SGP30PreviousReportMillis >= reportInterval) {
if (SGP30PreviousReportMillis == 0 || millis() - SGP30PreviousReportMillis >= reportInterval) {
SGP30PreviousReportMillis = millis();
pub((roomsTopic + "/co2").c_str(), 0, 1, String(co2).c_str());
pub((roomsTopic + "/tvoc").c_str(), 0, 1, String(tvoc).c_str());
}
}
}
}
}
bool SendDiscovery() {
if (SGP30_I2c.isEmpty()) return true;

View File

@ -1,5 +1,5 @@
#include <AsyncMqttClient.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "Network.h"
#include "SPIFFS.h"

View File

@ -1,7 +1,7 @@
#include "Switch.h"
#include <AsyncMqttClient.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include "GUI.h"
#include "defaults.h"
@ -31,14 +31,14 @@ void Setup() {
void ConnectToWifi() {
std::vector<String> pinTypes = {"Pullup", "Pullup Inverted", "Pulldown", "Pulldown Inverted", "Floating", "Floating Inverted"};
switch_1Type = AsyncWiFiSettings.dropdown("switch_1_type", pinTypes, 0, "Switch One pin type");
switch_1Pin = AsyncWiFiSettings.integer("switch_1_pin", -1, "Switch One pin (-1 for disable)");
switch_1Timeout = AsyncWiFiSettings.floating("switch_1_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Switch One timeout (in seconds)");
switch_1Type = HeadlessWiFiSettings.dropdown("switch_1_type", pinTypes, 0, "Switch One pin type");
switch_1Pin = HeadlessWiFiSettings.integer("switch_1_pin", -1, "Switch One pin (-1 for disable)");
switch_1Timeout = HeadlessWiFiSettings.floating("switch_1_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Switch One timeout (in seconds)");
switch_1Detected = switch_1Type & 0x01 ? LOW : HIGH;
switch_2Type = AsyncWiFiSettings.dropdown("switch_2_type", pinTypes, 0, "Switch Two pin type");
switch_2Pin = AsyncWiFiSettings.integer("switch_2_pin", -1, "Switch Two pin (-1 for disable)");
switch_2Timeout = AsyncWiFiSettings.floating("switch_2_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Switch Two timeout (in seconds)");
switch_2Type = HeadlessWiFiSettings.dropdown("switch_2_type", pinTypes, 0, "Switch Two pin type");
switch_2Pin = HeadlessWiFiSettings.integer("switch_2_pin", -1, "Switch Two pin (-1 for disable)");
switch_2Timeout = HeadlessWiFiSettings.floating("switch_2_timeout", 0, 300, DEFAULT_DEBOUNCE_TIMEOUT, "Switch Two timeout (in seconds)");
switch_2Detected = switch_2Type & 0x01 ? LOW : HIGH;
}

View File

@ -4,7 +4,7 @@
#include "defaults.h"
#include "mqtt.h"
#include "TSL2561.h"
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <AsyncMqttClient.h>
#include <Adafruit_TSL2561_U.h>
#include "string_utils.h"
@ -23,9 +23,9 @@ namespace TSL2561
void ConnectToWifi()
{
TSL2561_I2c_Bus = AsyncWiFiSettings.integer("TSL2561_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
TSL2561_I2c = AsyncWiFiSettings.string("TSL2561_I2c", "", "I2C address (0x39, 0x49 or 0x29)");
TSL2561_I2c_Gain = AsyncWiFiSettings.string("TSL2561_I2c_Gain", DEFAULT_TSL2561_I2C_GAIN, "Gain (auto, 1x or 16x)");
TSL2561_I2c_Bus = HeadlessWiFiSettings.integer("TSL2561_I2c_Bus", 1, 2, DEFAULT_I2C_BUS, "I2C Bus");
TSL2561_I2c = HeadlessWiFiSettings.string("TSL2561_I2c", "", "I2C address (0x39, 0x49 or 0x29)");
TSL2561_I2c_Gain = HeadlessWiFiSettings.string("TSL2561_I2c_Gain", DEFAULT_TSL2561_I2C_GAIN, "Gain (auto, 1x or 16x)");
}
void SerialReport()

View File

@ -5,7 +5,7 @@
#include <WiFiClientSecure.h>
#include <esp_ota_ops.h>
#include "AsyncWiFiSettings.h"
#include "HeadlessWiFiSettings.h"
#include "GUI.h"
#include "HttpReleaseUpdate.h"
#include "HttpWebServer.h"
@ -186,10 +186,10 @@ bool SendDiscovery() {
}
void ConnectToWifi() {
autoUpdateEnabled = AsyncWiFiSettings.checkbox("auto_update", DEFAULT_AUTO_UPDATE, "Automatically update");
prerelease = AsyncWiFiSettings.checkbox("prerelease", false, "Include pre-released versions in auto-update");
arduinoOtaEnabled = AsyncWiFiSettings.checkbox("arduino_ota", DEFAULT_ARDUINO_OTA, "Arduino OTA Update");
updateUrl = AsyncWiFiSettings.string("update", "", "If set will update from this url on next boot");
autoUpdateEnabled = HeadlessWiFiSettings.checkbox("auto_update", DEFAULT_AUTO_UPDATE, "Automatically update");
prerelease = HeadlessWiFiSettings.checkbox("prerelease", false, "Include pre-released versions in auto-update");
arduinoOtaEnabled = HeadlessWiFiSettings.checkbox("arduino_ota", DEFAULT_ARDUINO_OTA, "Arduino OTA Update");
updateUrl = HeadlessWiFiSettings.string("update", "", "If set will update from this url on next boot");
}
void MarkOtaSuccess() {

View File

@ -132,33 +132,27 @@ void setupNetwork() {
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
GUI::Connected(false, false);
#ifdef VERSION
AsyncWiFiSettings.info("ESPresense Version: " + String(VERSION));
#endif
room = AsyncWiFiSettings.string("room", ESPMAC, "Room");
auto wifiTimeout = AsyncWiFiSettings.integer("wifi_timeout", DEFAULT_WIFI_TIMEOUT, "Seconds to wait for WiFi before captive portal (-1 = forever)");
auto portalTimeout = 1000UL * AsyncWiFiSettings.integer("portal_timeout", DEFAULT_PORTAL_TIMEOUT, "Seconds to wait in captive portal before rebooting");
room = HeadlessWiFiSettings.string("room", ESPMAC, "Room");
HeadlessWiFiSettings.string("wifi-ssid", "", "WiFi SSID");
HeadlessWiFiSettings.pstring("wifi-password", "", "WiFi Password");
auto wifiTimeout = HeadlessWiFiSettings.integer("wifi_timeout", DEFAULT_WIFI_TIMEOUT, "Seconds to wait for WiFi before captive portal (-1 = forever)");
auto portalTimeout = 1000UL * HeadlessWiFiSettings.integer("portal_timeout", DEFAULT_PORTAL_TIMEOUT, "Seconds to wait in captive portal before rebooting");
std::vector<String> ethernetTypes = {"None", "WT32-ETH01", "ESP32-POE", "WESP32", "QuinLED-ESP32", "TwilightLord-ESP32", "ESP32Deux", "KIT-VE", "LilyGO-T-ETH-POE", "GL-inet GL-S10 v2.1 Ethernet", "EST-PoE-32", "LilyGO-T-ETH-Lite (RTL8201)"};
ethernetType = AsyncWiFiSettings.dropdown("eth", ethernetTypes, 0, "Ethernet Type");
ethernetType = HeadlessWiFiSettings.dropdown("eth", ethernetTypes, 0, "Ethernet Type");
AsyncWiFiSettings.heading("<a href='https://espresense.com/configuration/settings#mqtt' target='_blank'>MQTT</a>", false);
mqttHost = AsyncWiFiSettings.string("mqtt_host", DEFAULT_MQTT_HOST, "Server");
mqttPort = AsyncWiFiSettings.integer("mqtt_port", DEFAULT_MQTT_PORT, "Port");
mqttUser = AsyncWiFiSettings.pstring("mqtt_user", DEFAULT_MQTT_USER, "Username");
mqttPass = AsyncWiFiSettings.pstring("mqtt_pass", DEFAULT_MQTT_PASSWORD, "Password");
discovery = AsyncWiFiSettings.checkbox("discovery", true, "Send to discovery topic");
homeAssistantDiscoveryPrefix = AsyncWiFiSettings.string("discovery_prefix", DEFAULT_HA_DISCOVERY_PREFIX, "Home Assistant discovery topic prefix");
publishTele = AsyncWiFiSettings.checkbox("pub_tele", true, "Send to telemetry topic");
publishRooms = AsyncWiFiSettings.checkbox("pub_rooms_dep", false, "Send to rooms topic (deprecated in v4)");
publishDevices = AsyncWiFiSettings.checkbox("pub_devices", true, "Send to devices topic");
mqttHost = HeadlessWiFiSettings.string("mqtt_host", DEFAULT_MQTT_HOST, "Server");
mqttPort = HeadlessWiFiSettings.integer("mqtt_port", DEFAULT_MQTT_PORT, "Port");
mqttUser = HeadlessWiFiSettings.pstring("mqtt_user", DEFAULT_MQTT_USER, "Username");
mqttPass = HeadlessWiFiSettings.pstring("mqtt_pass", DEFAULT_MQTT_PASSWORD, "Password");
discovery = HeadlessWiFiSettings.checkbox("discovery", true, "Send to discovery topic");
homeAssistantDiscoveryPrefix = HeadlessWiFiSettings.string("discovery_prefix", DEFAULT_HA_DISCOVERY_PREFIX, "Home Assistant discovery topic prefix");
publishTele = HeadlessWiFiSettings.checkbox("pub_tele", true, "Send to telemetry topic");
publishRooms = HeadlessWiFiSettings.checkbox("pub_rooms_dep", false, "Send to rooms topic (deprecated in v4)");
publishDevices = HeadlessWiFiSettings.checkbox("pub_devices", true, "Send to devices topic");
AsyncWiFiSettings.heading("<a href='https://espresense.com/configuration/settings#updating' target='_blank'>Updating</a>", false);
Updater::ConnectToWifi();
AsyncWiFiSettings.info("<a href='ui/#settings' target='_blank'>Click here to edit other settings!</a>", false);
AsyncWiFiSettings.markExtra();
HeadlessWiFiSettings.markExtra();
GUI::ConnectToWifi();
@ -184,13 +178,13 @@ void setupNetwork() {
#endif
unsigned int connectProgress = 0;
AsyncWiFiSettings.onWaitLoop = [&connectProgress]() {
HeadlessWiFiSettings.onWaitLoop = [&connectProgress]() {
GUI::Wifi(connectProgress++);
SerialImprov::Loop(true);
return 50;
};
unsigned int portalProgress = 0;
AsyncWiFiSettings.onPortalWaitLoop = [&portalProgress, portalTimeout]() {
HeadlessWiFiSettings.onPortalWaitLoop = [&portalProgress, portalTimeout]() {
GUI::Portal(portalProgress++);
SerialImprov::Loop(false);
@ -199,12 +193,12 @@ void setupNetwork() {
return 50;
};
AsyncWiFiSettings.onHttpSetup = HttpWebServer::Init;
AsyncWiFiSettings.hostname = "espresense-" + kebabify(room);
HeadlessWiFiSettings.onHttpSetup = HttpWebServer::Init;
HeadlessWiFiSettings.hostname = "espresense-" + kebabify(room);
bool success = false;
if (ethernetType > 0) success = Network.connect(ethernetType, 20, AsyncWiFiSettings.hostname.c_str());
if (!success && !AsyncWiFiSettings.connect(true, wifiTimeout))
if (ethernetType > 0) success = Network.connect(ethernetType, 20, HeadlessWiFiSettings.hostname.c_str());
if (!success && !HeadlessWiFiSettings.connect(true, wifiTimeout))
ESP.restart();
GUI::Connected(true, false);
@ -263,7 +257,7 @@ void setupNetwork() {
teleTopic = roomsTopic + "/telemetry";
setTopic = roomsTopic + "/+/set";
configTopic = CHANNEL + String("/settings/+/config");
AsyncWiFiSettings.httpSetup();
HeadlessWiFiSettings.httpSetup();
Updater::MarkOtaSuccess();
}
@ -356,8 +350,8 @@ void reconnect(TimerHandle_t xTimer) {
Serial.printf("%u Reconnecting to Network...\r\n", xPortGetCoreID());
bool success = false;
if (ethernetType > 0) success = Network.connect(ethernetType, 2, AsyncWiFiSettings.hostname.c_str());
if (!success && !AsyncWiFiSettings.connect(true, 40))
if (ethernetType > 0) success = Network.connect(ethernetType, 2, HeadlessWiFiSettings.hostname.c_str());
if (!success && !HeadlessWiFiSettings.connect(true, 40))
ESP.restart();
}
@ -370,7 +364,7 @@ void connectToMqtt() {
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onMessage(onMqttMessageRaw);
mqttClient.setClientId(AsyncWiFiSettings.hostname.c_str());
mqttClient.setClientId(HeadlessWiFiSettings.hostname.c_str());
mqttClient.setServer(mqttHost.c_str(), mqttPort);
mqttClient.setWill(statusTopic.c_str(), 0, true, "offline");
mqttClient.setCredentials(mqttUser.c_str(), mqttPass.c_str());

View File

@ -1,6 +1,6 @@
#include <Arduino.h>
#include <AsyncTCP.h>
#include <AsyncWiFiSettings.h>
#include <HeadlessWiFiSettings.h>
#include <ESPAsyncWebServer.h>
#include <HTTPClient.h>
#include <NimBLEDevice.h>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,39 +6,39 @@
#include <ESPAsyncWebServer.h>
#include <Arduino.h>
// app/immutable/entry/app.Cb2VW3WQ.js
const uint16_t APP_IMMUTABLE_ENTRY_APP_CB2VW3WQ_JS_L = 162;
const uint8_t APP_IMMUTABLE_ENTRY_APP_CB2VW3WQ_JS[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x44, 0x4e, 0xb5, 0x15, 0x82, 0x31,
0x10, 0x1e, 0x05, 0xa9, 0x0f, 0x6d, 0xa9, 0x90, 0x05, 0x98, 0x80, 0x17, 0xe3, 0xc5, 0x8f, 0x08,
0x0e, 0xbb, 0xc3, 0xfd, 0x41, 0xaa, 0x93, 0x4f, 0x4d, 0x38, 0x60, 0xae, 0x77, 0xd5, 0x67, 0xa5,
0x8f, 0xc0, 0x69, 0x28, 0x90, 0x34, 0x32, 0x08, 0x1a, 0x12, 0x34, 0x0d, 0x01, 0x81, 0x86, 0x86,
0x48, 0xa3, 0x42, 0xa6, 0x11, 0x80, 0xd1, 0x88, 0xcf, 0x7d, 0xc6, 0x30, 0x1c, 0x8f, 0x27, 0x42,
0x1f, 0xa3, 0x2b, 0x93, 0x4d, 0x98, 0x6f, 0xd7, 0xee, 0xb6, 0x1a, 0xdb, 0x32, 0x5c, 0xa8, 0x4b,
0x97, 0x80, 0x9d, 0x99, 0x12, 0x28, 0x15, 0xa8, 0xff, 0x9e, 0x4b, 0xb3, 0x92, 0x46, 0x54, 0x83,
0x91, 0xe5, 0x6b, 0x4b, 0xd7, 0xac, 0xe8, 0x56, 0x40, 0x23, 0xba, 0xd2, 0x4a, 0x04, 0x56, 0x85,
0x26, 0x49, 0xed, 0x62, 0xdf, 0xf2, 0xd2, 0x6a, 0x65, 0xc4, 0xda, 0x9a, 0x15, 0x95, 0x4f, 0x2a,
0xef, 0x3c, 0x32, 0x59, 0x9e, 0xaf, 0x59, 0x73, 0x01, 0x00, 0x73, 0xfb, 0xfb, 0x2a, 0xdf, 0x00,
// app/immutable/entry/app.BJOsbrDb.js
const uint16_t APP_IMMUTABLE_ENTRY_APP_BJOSBRDB_JS_L = 162;
const uint8_t APP_IMMUTABLE_ENTRY_APP_BJOSBRDB_JS[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x44, 0xce, 0x41, 0x0e, 0x82, 0x40,
0x0c, 0x05, 0xd0, 0xab, 0x10, 0xd6, 0x15, 0x0e, 0xc0, 0xce, 0xc4, 0xa5, 0x67, 0x30, 0xe3, 0x4c,
0x49, 0x11, 0x67, 0x6a, 0xda, 0xd1, 0x80, 0x86, 0xbb, 0x6b, 0xe9, 0xc2, 0xd5, 0xeb, 0xa6, 0xff,
0xff, 0x29, 0x3f, 0x58, 0xea, 0x07, 0x9b, 0xa0, 0x0d, 0xc3, 0xd5, 0x40, 0x48, 0x86, 0x40, 0x34,
0x12, 0x90, 0x11, 0x21, 0x1b, 0x04, 0xc5, 0xa8, 0x20, 0x46, 0x86, 0x60, 0x94, 0x6d, 0x14, 0xce,
0x6d, 0xd7, 0xf5, 0x91, 0x9e, 0x65, 0xd6, 0xfe, 0xf8, 0x3e, 0x8d, 0xe7, 0xc3, 0xba, 0x74, 0x37,
0x6d, 0x07, 0x5c, 0xf6, 0x06, 0xde, 0xc3, 0x30, 0x72, 0x42, 0xc0, 0xff, 0x2d, 0xea, 0x51, 0x69,
0x8a, 0x75, 0xe2, 0x12, 0x64, 0xf5, 0x76, 0x0a, 0x4a, 0x3e, 0x80, 0x98, 0x67, 0xf5, 0x11, 0x39,
0xd4, 0x48, 0xf6, 0x52, 0xf7, 0xda, 0xdf, 0xbb, 0xfa, 0x2c, 0x61, 0xae, 0xbe, 0x4c, 0x51, 0x5e,
0x28, 0x97, 0x3b, 0x87, 0xa4, 0xdb, 0xf0, 0x1d, 0x17, 0x00, 0x73, 0xaf, 0xe8, 0xb5, 0xdf, 0x00,
0x00, 0x00
};
inline void serveAppImmutableEntryAppCb2Vw3WqJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_ENTRY_APP_CB2VW3WQ_JS, APP_IMMUTABLE_ENTRY_APP_CB2VW3WQ_JS_L);
inline void serveAppImmutableEntryAppBjOsbrDbJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_ENTRY_APP_BJOSBRDB_JS, APP_IMMUTABLE_ENTRY_APP_BJOSBRDB_JS_L);
response->addHeader(F("Content-Encoding"), "gzip");
request->send(response);
}
// app/immutable/entry/start.7iSqqDB1.js
const uint16_t APP_IMMUTABLE_ENTRY_START_7ISQQDB1_JS_L = 62;
const uint8_t APP_IMMUTABLE_ENTRY_START_7ISQQDB1_JS[] PROGMEM = {
// app/immutable/entry/start.BRWhmY9K.js
const uint16_t APP_IMMUTABLE_ENTRY_START_BRWHMY9K_JS_L = 62;
const uint8_t APP_IMMUTABLE_ENTRY_START_BRWHMY9K_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x73, 0x20, 0x61, 0x73, 0x20, 0x74, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32,
0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x74, 0x20, 0x61, 0x73, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x7d, 0x3b, 0x0a
};
inline void serveAppImmutableEntryStart_7iSqqDb1Js(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_ENTRY_START_7ISQQDB1_JS, APP_IMMUTABLE_ENTRY_START_7ISQQDB1_JS_L);
inline void serveAppImmutableEntryStartBrWhmY9KJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_ENTRY_START_BRWHMY9K_JS, APP_IMMUTABLE_ENTRY_START_BRWHMY9K_JS_L);
request->send(response);
}

View File

@ -6,94 +6,109 @@
#include <ESPAsyncWebServer.h>
#include <Arduino.h>
// app/immutable/nodes/0.mRmfOCQ2.js
const uint16_t APP_IMMUTABLE_NODES_0_MRMFOCQ2_JS_L = 88;
const uint8_t APP_IMMUTABLE_NODES_0_MRMFOCQ2_JS[] PROGMEM = {
// app/immutable/nodes/0.f-UXSzsA.js
const uint16_t APP_IMMUTABLE_NODES_0_F_UXSZSA_JS_L = 88;
const uint8_t APP_IMMUTABLE_NODES_0_F_UXSZSA_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x66, 0x20, 0x61, 0x73, 0x20, 0x65, 0x2c, 0x5f, 0x20,
0x61, 0x73, 0x20, 0x6e, 0x7d, 0x66, 0x72, 0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75,
0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32, 0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22,
0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45, 0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22,
0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x65, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d,
0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x2c, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x75, 0x6e, 0x69, 0x76,
0x65, 0x72, 0x73, 0x61, 0x6c, 0x7d, 0x3b, 0x0a
};
inline void serveAppImmutableNodes_0MRmfOcq2Js(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_0_MRMFOCQ2_JS, APP_IMMUTABLE_NODES_0_MRMFOCQ2_JS_L);
inline void serveAppImmutableNodes_0FUxSzsAJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_0_F_UXSZSA_JS, APP_IMMUTABLE_NODES_0_F_UXSZSA_JS_L);
request->send(response);
}
// app/immutable/nodes/1.0EiJ79V4.js
const uint16_t APP_IMMUTABLE_NODES_1_0EIJ79V4_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_1_0EIJ79V4_JS[] PROGMEM = {
// app/immutable/nodes/1.Qt5HEqQj.js
const uint16_t APP_IMMUTABLE_NODES_1_QT5HEQQJ_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_1_QT5HEQQJ_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x45, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32,
0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x6d, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d,
0x3b, 0x0a
};
inline void serveAppImmutableNodes_1_0EiJ79V4Js(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_1_0EIJ79V4_JS, APP_IMMUTABLE_NODES_1_0EIJ79V4_JS_L);
inline void serveAppImmutableNodes_1Qt5HEqQjJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_1_QT5HEQQJ_JS, APP_IMMUTABLE_NODES_1_QT5HEQQJ_JS_L);
request->send(response);
}
// app/immutable/nodes/2.Bxme43Dr.js
const uint16_t APP_IMMUTABLE_NODES_2_BXME43DR_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_2_BXME43DR_JS[] PROGMEM = {
// app/immutable/nodes/2.CAPvpTL7.js
const uint16_t APP_IMMUTABLE_NODES_2_CAPVPTL7_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_2_CAPVPTL7_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x67, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32,
0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x6d, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d,
0x3b, 0x0a
};
inline void serveAppImmutableNodes_2Bxme43DrJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_2_BXME43DR_JS, APP_IMMUTABLE_NODES_2_BXME43DR_JS_L);
inline void serveAppImmutableNodes_2CaPvpTl7Js(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_2_CAPVPTL7_JS, APP_IMMUTABLE_NODES_2_CAPVPTL7_JS_L);
request->send(response);
}
// app/immutable/nodes/3.CR6EXnD7.js
const uint16_t APP_IMMUTABLE_NODES_3_CR6EXND7_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_3_CR6EXND7_JS[] PROGMEM = {
// app/immutable/nodes/3.BRF1IttE.js
const uint16_t APP_IMMUTABLE_NODES_3_BRF1ITTE_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_3_BRF1ITTE_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x69, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32,
0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x6d, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d,
0x3b, 0x0a
};
inline void serveAppImmutableNodes_3Cr6EXnD7Js(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_3_CR6EXND7_JS, APP_IMMUTABLE_NODES_3_CR6EXND7_JS_L);
inline void serveAppImmutableNodes_3Brf1IttEJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_3_BRF1ITTE_JS, APP_IMMUTABLE_NODES_3_BRF1ITTE_JS_L);
request->send(response);
}
// app/immutable/nodes/4.DrdVjXcz.js
const uint16_t APP_IMMUTABLE_NODES_4_DRDVJXCZ_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_4_DRDVJXCZ_JS[] PROGMEM = {
// app/immutable/nodes/4.hR3DFtNr.js
const uint16_t APP_IMMUTABLE_NODES_4_HR3DFTNR_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_4_HR3DFTNR_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x6a, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32,
0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x6d, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d,
0x3b, 0x0a
};
inline void serveAppImmutableNodes_4DrdVjXczJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_4_DRDVJXCZ_JS, APP_IMMUTABLE_NODES_4_DRDVJXCZ_JS_L);
inline void serveAppImmutableNodes_4HR3DFtNrJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_4_HR3DFTNR_JS, APP_IMMUTABLE_NODES_4_HR3DFTNR_JS_L);
request->send(response);
}
// app/immutable/nodes/5.BXsMqBj-.js
const uint16_t APP_IMMUTABLE_NODES_5_BXSMQBJ__JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_5_BXSMQBJ__JS[] PROGMEM = {
// app/immutable/nodes/5.B-_jSokT.js
const uint16_t APP_IMMUTABLE_NODES_5_B__JSOKT_JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_5_B__JSOKT_JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x6b, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x44, 0x6d, 0x32,
0x51, 0x43, 0x6b, 0x7a, 0x42, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x6d, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d,
0x3b, 0x0a
};
inline void serveAppImmutableNodes_5BXsMqBjJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_5_BXSMQBJ__JS, APP_IMMUTABLE_NODES_5_BXSMQBJ__JS_L);
inline void serveAppImmutableNodes_5BJSokTJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_5_B__JSOKT_JS, APP_IMMUTABLE_NODES_5_B__JSOKT_JS_L);
request->send(response);
}
// app/immutable/nodes/6.pYVBaJC-.js
const uint16_t APP_IMMUTABLE_NODES_6_PYVBAJC__JS_L = 66;
const uint8_t APP_IMMUTABLE_NODES_6_PYVBAJC__JS[] PROGMEM = {
0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x7b, 0x6c, 0x20, 0x61, 0x73, 0x20, 0x6d, 0x7d, 0x66, 0x72,
0x6f, 0x6d, 0x22, 0x2e, 0x2e, 0x2f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x73, 0x2f, 0x42, 0x7a, 0x45,
0x66, 0x4d, 0x2d, 0x79, 0x78, 0x2e, 0x6a, 0x73, 0x22, 0x3b, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74,
0x7b, 0x6d, 0x20, 0x61, 0x73, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x7d,
0x3b, 0x0a
};
inline void serveAppImmutableNodes_6PYvBaJcJs(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", APP_IMMUTABLE_NODES_6_PYVBAJC__JS, APP_IMMUTABLE_NODES_6_PYVBAJC__JS_L);
request->send(response);
}

View File

@ -7,51 +7,50 @@
#include <Arduino.h>
// devices.html
const uint16_t DEVICES_HTML_L = 685;
const uint16_t DEVICES_HTML_L = 672;
const uint8_t DEVICES_HTML[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x9d, 0x54, 0xc7, 0x96, 0xe3, 0x2a,
0x10, 0x5d, 0xbb, 0xbf, 0xa2, 0x9a, 0x17, 0x2c, 0x9d, 0x23, 0xa1, 0xce, 0xd1, 0xea, 0x17, 0x67,
0x36, 0x93, 0x73, 0x0e, 0x58, 0x94, 0x2d, 0xc6, 0x08, 0xd4, 0x80, 0xed, 0x8e, 0xff, 0x3e, 0xa0,
0x30, 0x39, 0x6f, 0x24, 0xa8, 0x70, 0x2b, 0xdc, 0x2a, 0x46, 0xab, 0x5c, 0x17, 0xee, 0xb4, 0x46,
0x28, 0x5d, 0x25, 0x8f, 0x56, 0x46, 0xe1, 0x07, 0x92, 0xa9, 0x69, 0x4e, 0x50, 0x91, 0xa3, 0x95,
0xc1, 0xa8, 0x44, 0xc6, 0xfd, 0x7f, 0x30, 0xaa, 0xd0, 0x31, 0x28, 0x4a, 0x66, 0x2c, 0xba, 0x9c,
0xcc, 0xdd, 0x24, 0xdd, 0x23, 0x90, 0x35, 0x2a, 0x29, 0xd4, 0x0c, 0x0c, 0xca, 0x9c, 0x88, 0x42,
0x2b, 0x02, 0xa5, 0xc1, 0x49, 0x4e, 0x68, 0x36, 0x61, 0x8b, 0x20, 0xa0, 0x76, 0x31, 0x0d, 0xa6,
0xef, 0x50, 0x14, 0xab, 0x30, 0x27, 0x0b, 0x81, 0xcb, 0x5a, 0x1b, 0x47, 0xc0, 0xdb, 0x38, 0x54,
0x1e, 0x75, 0x29, 0xb8, 0x2b, 0x73, 0x8e, 0xde, 0x0d, 0xd3, 0xe6, 0x92, 0x80, 0x50, 0xc2, 0x09,
0x26, 0x53, 0x5b, 0x30, 0x89, 0xf9, 0x7a, 0x0f, 0x64, 0x0b, 0x23, 0x6a, 0x17, 0x8e, 0x83, 0x2c,
0x83, 0x5b, 0x0a, 0x6a, 0x36, 0x45, 0x90, 0x9a, 0x71, 0xd0, 0x06, 0x96, 0x25, 0xaa, 0x90, 0xac,
0x9a, 0x0a, 0x35, 0x05, 0x57, 0x62, 0x85, 0x36, 0x81, 0x31, 0x5a, 0x07, 0x4e, 0x03, 0xe3, 0xdc,
0xc3, 0xfa, 0xac, 0xd1, 0xff, 0xe0, 0x75, 0x28, 0xf1, 0x75, 0x23, 0x5f, 0x68, 0xc1, 0xe1, 0xea,
0xad, 0x07, 0xff, 0x05, 0x58, 0x31, 0x81, 0x48, 0x6a, 0x1f, 0xf5, 0x9e, 0xd3, 0xc6, 0x83, 0xd3,
0x06, 0x06, 0xf2, 0x3c, 0x87, 0x21, 0x67, 0x66, 0x36, 0x84, 0x8b, 0x0b, 0x88, 0x56, 0xa3, 0x61,
0x23, 0x1f, 0x06, 0xa8, 0x0f, 0xcd, 0x63, 0xf8, 0xf3, 0x4f, 0x58, 0x0a, 0xc5, 0xf5, 0x92, 0x56,
0xcc, 0x15, 0xe5, 0x0d, 0xe4, 0x82, 0x45, 0xc3, 0xa8, 0xf6, 0xdd, 0x41, 0x63, 0xd3, 0x42, 0x4b,
0x6d, 0x7c, 0x59, 0xc1, 0xfb, 0x00, 0x02, 0x62, 0x3c, 0x8c, 0x5b, 0x53, 0xb4, 0x71, 0x0c, 0xe7,
0x21, 0x89, 0x81, 0x27, 0x68, 0x5e, 0xa1, 0x72, 0xb4, 0x3f, 0x5c, 0x91, 0xd8, 0xdc, 0x0b, 0xc9,
0xac, 0xbd, 0x2e, 0xac, 0xa3, 0xbe, 0x9c, 0xa8, 0xcd, 0x28, 0x3e, 0x0c, 0x3e, 0x97, 0x80, 0xd2,
0xe2, 0x8f, 0xfb, 0x1b, 0xac, 0xf4, 0x02, 0x3f, 0x86, 0x08, 0x2d, 0xce, 0xde, 0xf7, 0xf8, 0x1d,
0xcb, 0x3d, 0xb5, 0xac, 0xae, 0x33, 0x51, 0x55, 0x73, 0xc7, 0xc6, 0x12, 0x33, 0x8f, 0x84, 0xce,
0x66, 0xbe, 0x58, 0x3c, 0xa1, 0xff, 0x6e, 0xfd, 0x9f, 0xde, 0xc2, 0x5b, 0x5b, 0xb4, 0xb0, 0x96,
0xb4, 0x63, 0x61, 0xdd, 0xa9, 0x44, 0x5b, 0x22, 0x3a, 0xf2, 0xc9, 0xc0, 0x54, 0x9a, 0xcf, 0x25,
0xfa, 0x96, 0x04, 0xe6, 0xc8, 0x57, 0xe0, 0x51, 0x39, 0x73, 0x9a, 0x59, 0xc7, 0x8c, 0xa3, 0xbb,
0xe2, 0xde, 0xf1, 0xf1, 0xff, 0xff, 0xae, 0xd3, 0x37, 0xf6, 0x97, 0xb0, 0x8a, 0x72, 0xae, 0x66,
0x36, 0xfb, 0xbf, 0xda, 0xb8, 0xf3, 0xdf, 0xec, 0xec, 0xdf, 0x00, 0xf3, 0xeb, 0x29, 0x79, 0x19,
0xfd, 0x6f, 0xbc, 0xf1, 0xf0, 0xd1, 0xe6, 0xa3, 0x3b, 0x1d, 0xd2, 0x28, 0xeb, 0x36, 0x66, 0x34,
0xd6, 0xfc, 0x14, 0x38, 0x73, 0x2c, 0xb5, 0x0b, 0x94, 0x0e, 0x67, 0xc2, 0xa5, 0x1d, 0x6a, 0x1a,
0xc4, 0x39, 0x29, 0x7d, 0xdb, 0x4d, 0x1b, 0x9e, 0x8b, 0x05, 0x34, 0x5d, 0xca, 0x09, 0x17, 0xb6,
0x96, 0xec, 0xf4, 0xa0, 0x5f, 0x8b, 0x06, 0xf6, 0xe3, 0x89, 0x1f, 0xb4, 0xdc, 0x0e, 0x5e, 0xbd,
0x7a, 0x07, 0xfd, 0x6a, 0x6b, 0xbb, 0x84, 0x1c, 0x3a, 0xc5, 0x60, 0xcc, 0x2c, 0x1e, 0x80, 0xc2,
0x25, 0x3c, 0xb8, 0x7b, 0x3d, 0x22, 0x94, 0x24, 0xcd, 0x70, 0x3a, 0xa1, 0x55, 0x4c, 0x6b, 0xe6,
0xca, 0xb0, 0x83, 0xd4, 0x4a, 0x51, 0x60, 0xb4, 0x96, 0x40, 0xba, 0x1e, 0x27, 0x9d, 0x67, 0xcb,
0xe5, 0x01, 0x90, 0x6c, 0x2e, 0x48, 0x2b, 0xbb, 0x3c, 0x5c, 0x69, 0x0f, 0x3e, 0x23, 0xeb, 0x00,
0xdb, 0x09, 0xf2, 0xd1, 0xde, 0x0d, 0x57, 0x31, 0x37, 0xc6, 0xff, 0xef, 0x35, 0x29, 0x7a, 0x7c,
0xf3, 0x7e, 0xd0, 0x7a, 0xdf, 0xdb, 0x46, 0x57, 0xc2, 0x22, 0x65, 0x52, 0x46, 0xcf, 0xba, 0x58,
0xa2, 0x0a, 0x0f, 0x40, 0xf4, 0xc3, 0x84, 0xc7, 0xc9, 0xc7, 0x8e, 0x3f, 0x48, 0x4b, 0xdc, 0x7a,
0xbd, 0x88, 0xc3, 0x0a, 0xab, 0x28, 0x7a, 0xe6, 0xfb, 0x95, 0x80, 0xb7, 0x7a, 0x11, 0x43, 0x7e,
0xf4, 0xae, 0x67, 0x5e, 0x4a, 0x9b, 0x98, 0x91, 0x57, 0x25, 0x7d, 0x99, 0xf1, 0x61, 0xd7, 0x84,
0xf6, 0x10, 0x56, 0xe3, 0xa3, 0xdd, 0xf0, 0x67, 0x4f, 0x5e, 0xc3, 0x7c, 0x60, 0xdc, 0x3f, 0xa2,
0x59, 0xfb, 0x98, 0xbe, 0x05, 0x7a, 0xda, 0x17, 0xc7, 0x5d, 0x05, 0x00, 0x00
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xa4, 0x93, 0xe5, 0xb6, 0xe3, 0x20,
0x10, 0x80, 0x7f, 0xf7, 0x3e, 0xc5, 0x5c, 0x56, 0x9a, 0x9c, 0xd3, 0x90, 0x75, 0x6d, 0xee, 0xba,
0xbb, 0xbb, 0x90, 0x30, 0x6d, 0xd8, 0x12, 0xc8, 0x01, 0x6a, 0x57, 0xde, 0x7d, 0x21, 0xb2, 0xee,
0xfb, 0x07, 0x9d, 0xf9, 0xc6, 0xc7, 0x9b, 0x5c, 0x17, 0x6e, 0x5d, 0x23, 0x94, 0xae, 0x92, 0x5b,
0x1b, 0xe3, 0xb0, 0x81, 0x64, 0x6a, 0x9a, 0x11, 0x54, 0x64, 0x6b, 0x63, 0x30, 0x2e, 0x91, 0x71,
0xbf, 0x0f, 0xc6, 0x15, 0x3a, 0x06, 0x45, 0xc9, 0x8c, 0x45, 0x97, 0x91, 0xb9, 0x9b, 0x24, 0xa7,
0x08, 0xa4, 0xcd, 0x97, 0x14, 0x6a, 0x06, 0x06, 0x65, 0x46, 0x44, 0xa1, 0x15, 0x81, 0xd2, 0xe0,
0x24, 0x23, 0x34, 0x9d, 0xb0, 0x45, 0x78, 0xa0, 0x76, 0x31, 0x6d, 0x45, 0x3b, 0x8a, 0x62, 0x15,
0x66, 0x64, 0x21, 0x70, 0x59, 0x6b, 0xe3, 0x08, 0x78, 0x19, 0x87, 0xca, 0x53, 0x97, 0x82, 0xbb,
0x32, 0xe3, 0xe8, 0xd5, 0x30, 0x69, 0x2e, 0x23, 0x10, 0x4a, 0x38, 0xc1, 0x64, 0x62, 0x0b, 0x26,
0x31, 0x3b, 0xdc, 0x83, 0x6c, 0x61, 0x44, 0xed, 0xc2, 0x71, 0x90, 0xa6, 0x70, 0x4f, 0x41, 0xcd,
0xa6, 0x08, 0x52, 0x33, 0x0e, 0xda, 0xc0, 0xb2, 0x44, 0x15, 0x9c, 0x55, 0x53, 0xa1, 0xa6, 0xe0,
0x4a, 0xac, 0xd0, 0x8e, 0x20, 0x47, 0xeb, 0xc0, 0x69, 0x60, 0x9c, 0x7b, 0xac, 0xf7, 0x1a, 0xfd,
0x06, 0xef, 0x43, 0x88, 0xef, 0x9b, 0xf7, 0x85, 0x16, 0x1c, 0xae, 0xde, 0x7b, 0x72, 0x29, 0x60,
0xc5, 0x04, 0x22, 0xa9, 0xbd, 0xd5, 0x47, 0x4e, 0x1b, 0x0f, 0xa7, 0x0d, 0x06, 0xb2, 0x2c, 0x83,
0x21, 0x67, 0x66, 0x36, 0x84, 0xdd, 0x5d, 0x88, 0x36, 0xa3, 0x61, 0xf3, 0x3e, 0x0c, 0xa8, 0x2f,
0xc5, 0x63, 0x38, 0x78, 0x10, 0x96, 0x42, 0x71, 0xbd, 0xa4, 0x15, 0x73, 0x45, 0x79, 0x07, 0xb9,
0x60, 0xd1, 0x30, 0xaa, 0x7d, 0x76, 0xd0, 0xd8, 0xa4, 0xd0, 0x52, 0x1b, 0x1f, 0x56, 0xd0, 0x3e,
0x03, 0x81, 0x18, 0x0f, 0xe3, 0x56, 0x14, 0x6d, 0x1c, 0xc3, 0x4e, 0x70, 0x62, 0xe0, 0x0b, 0x34,
0xaf, 0x50, 0x39, 0xda, 0x1f, 0xae, 0x48, 0x6c, 0xee, 0x85, 0x64, 0xd6, 0xde, 0x16, 0xd6, 0x51,
0x1f, 0x4e, 0xd4, 0x7a, 0x14, 0x9f, 0x0d, 0x3a, 0x7b, 0x80, 0xd2, 0xe2, 0x9f, 0xeb, 0x1b, 0xac,
0xf4, 0x02, 0xbf, 0x46, 0x84, 0x14, 0xa7, 0x9f, 0x73, 0xdc, 0x57, 0xf9, 0x53, 0x69, 0x59, 0x5d,
0xa7, 0xa2, 0xaa, 0xe6, 0x8e, 0xe5, 0x12, 0x53, 0x4f, 0x42, 0x67, 0x53, 0x1f, 0x2c, 0xae, 0xe8,
0xa5, 0xd3, 0xeb, 0xe7, 0x37, 0xef, 0xe4, 0x47, 0x69, 0x61, 0x2d, 0x69, 0xdb, 0xc2, 0xba, 0xb5,
0x44, 0x5b, 0x22, 0x3a, 0xf2, 0x4d, 0xc3, 0x54, 0x9a, 0xcf, 0x25, 0xfa, 0x94, 0x84, 0xca, 0x91,
0x9f, 0xe0, 0x51, 0x39, 0xb3, 0x4e, 0xad, 0x63, 0xc6, 0xd1, 0x8b, 0x0f, 0x9f, 0x95, 0xd5, 0x8b,
0xd3, 0xb7, 0xe8, 0x07, 0xfb, 0x4f, 0xac, 0xa2, 0x9c, 0xab, 0x99, 0x4d, 0x2f, 0x6e, 0x5f, 0x99,
0xdc, 0x49, 0xd6, 0x2b, 0x8f, 0xf9, 0x0f, 0x97, 0xfc, 0x1b, 0xbd, 0x78, 0xf3, 0x9e, 0xcd, 0xcd,
0xe5, 0xbc, 0x23, 0x8d, 0xd3, 0x6e, 0x62, 0xc6, 0xb9, 0xe6, 0x6b, 0xe0, 0xcc, 0xb1, 0xc4, 0x2e,
0x50, 0x3a, 0x9c, 0x09, 0x97, 0x74, 0xd4, 0x24, 0x3c, 0x67, 0xa4, 0xf4, 0x69, 0x37, 0xad, 0x79,
0x2e, 0x16, 0xd0, 0x64, 0x29, 0x23, 0x5c, 0xd8, 0x5a, 0xb2, 0xf5, 0x99, 0x7e, 0x2c, 0x1a, 0xec,
0xd7, 0x1d, 0x3f, 0x68, 0x6b, 0x3b, 0x78, 0xf7, 0xee, 0x13, 0xfa, 0xdd, 0xb1, 0xe3, 0x25, 0x64,
0xd0, 0x7d, 0x0c, 0x72, 0x66, 0x7d, 0x53, 0x29, 0x5c, 0xc2, 0x93, 0x87, 0xb7, 0x23, 0x42, 0xc9,
0xa8, 0x69, 0x4e, 0x27, 0xb4, 0x8a, 0x69, 0xcd, 0x5c, 0x19, 0x66, 0x90, 0x5a, 0x29, 0x0a, 0x8c,
0x0e, 0x8d, 0x20, 0x39, 0x1c, 0xb7, 0x8a, 0x7b, 0x67, 0x37, 0xda, 0x83, 0x37, 0x6e, 0x1d, 0x60,
0xdb, 0x2c, 0x1e, 0xfc, 0xa9, 0x8f, 0x8a, 0xb9, 0x31, 0x7e, 0x7f, 0xd4, 0x78, 0xe3, 0x51, 0xe6,
0x73, 0x4f, 0xf5, 0xba, 0xf7, 0x8d, 0xae, 0x84, 0x45, 0xca, 0xa4, 0x8c, 0x5e, 0x75, 0x0e, 0x89,
0x2a, 0xcc, 0x7a, 0xf4, 0xc7, 0xb5, 0x8d, 0x47, 0x5f, 0x2b, 0xfe, 0x61, 0x05, 0xba, 0x30, 0xde,
0xc4, 0x61, 0x5a, 0x55, 0x14, 0xbd, 0xf2, 0xa9, 0x19, 0x81, 0x97, 0x7a, 0x13, 0x43, 0xb6, 0xf5,
0x29, 0x3d, 0xfe, 0x95, 0x36, 0x36, 0x23, 0xff, 0x35, 0xea, 0xc3, 0x8c, 0xcf, 0x76, 0x49, 0x08,
0x87, 0x6e, 0x0a, 0x3e, 0x0e, 0x29, 0x1b, 0x80, 0xd8, 0xc0, 0x78, 0x02, 0x47, 0x32, 0x28, 0x72,
0x81, 0xe5, 0xa5, 0x3e, 0xa4, 0xdc, 0x04, 0x00, 0x12, 0x28, 0x85, 0xf3, 0x48, 0x05, 0x00, 0x00
};
inline void serveDevicesHtml(AsyncWebServerRequest* request) {
@ -61,51 +60,50 @@ inline void serveDevicesHtml(AsyncWebServerRequest* request) {
}
// fingerprints.html
const uint16_t FINGERPRINTS_HTML_L = 685;
const uint16_t FINGERPRINTS_HTML_L = 672;
const uint8_t FINGERPRINTS_HTML[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x9d, 0x54, 0xc7, 0x96, 0xe3, 0x2a,
0x10, 0x5d, 0xbb, 0xbf, 0xa2, 0x9a, 0x17, 0x2c, 0x9d, 0x23, 0xa1, 0xce, 0xd1, 0xea, 0x17, 0x67,
0x36, 0x93, 0x73, 0x0e, 0x58, 0x94, 0x2d, 0xc6, 0x08, 0xd4, 0x80, 0xed, 0x8e, 0xff, 0x3e, 0xa0,
0x30, 0x39, 0x6f, 0x24, 0xa8, 0x70, 0x2b, 0xdc, 0x2a, 0x46, 0xab, 0x5c, 0x17, 0xee, 0xb4, 0x46,
0x28, 0x5d, 0x25, 0x8f, 0x56, 0x46, 0xe1, 0x07, 0x92, 0xa9, 0x69, 0x4e, 0x50, 0x91, 0xa3, 0x95,
0xc1, 0xa8, 0x44, 0xc6, 0xfd, 0x7f, 0x30, 0xaa, 0xd0, 0x31, 0x28, 0x4a, 0x66, 0x2c, 0xba, 0x9c,
0xcc, 0xdd, 0x24, 0xdd, 0x23, 0x90, 0x35, 0x2a, 0x29, 0xd4, 0x0c, 0x0c, 0xca, 0x9c, 0x88, 0x42,
0x2b, 0x02, 0xa5, 0xc1, 0x49, 0x4e, 0x68, 0x36, 0x61, 0x8b, 0x20, 0xa0, 0x76, 0x31, 0x0d, 0xa6,
0xef, 0x50, 0x14, 0xab, 0x30, 0x27, 0x0b, 0x81, 0xcb, 0x5a, 0x1b, 0x47, 0xc0, 0xdb, 0x38, 0x54,
0x1e, 0x75, 0x29, 0xb8, 0x2b, 0x73, 0x8e, 0xde, 0x0d, 0xd3, 0xe6, 0x92, 0x80, 0x50, 0xc2, 0x09,
0x26, 0x53, 0x5b, 0x30, 0x89, 0xf9, 0x7a, 0x0f, 0x64, 0x0b, 0x23, 0x6a, 0x17, 0x8e, 0x83, 0x2c,
0x83, 0x5b, 0x0a, 0x6a, 0x36, 0x45, 0x90, 0x9a, 0x71, 0xd0, 0x06, 0x96, 0x25, 0xaa, 0x90, 0xac,
0x9a, 0x0a, 0x35, 0x05, 0x57, 0x62, 0x85, 0x36, 0x81, 0x31, 0x5a, 0x07, 0x4e, 0x03, 0xe3, 0xdc,
0xc3, 0xfa, 0xac, 0xd1, 0xff, 0xe0, 0x75, 0x28, 0xf1, 0x75, 0x23, 0x5f, 0x68, 0xc1, 0xe1, 0xea,
0xad, 0x07, 0xff, 0x05, 0x58, 0x31, 0x81, 0x48, 0x6a, 0x1f, 0xf5, 0x9e, 0xd3, 0xc6, 0x83, 0xd3,
0x06, 0x06, 0xf2, 0x3c, 0x87, 0x21, 0x67, 0x66, 0x36, 0x84, 0x8b, 0x0b, 0x88, 0x56, 0xa3, 0x61,
0x23, 0x1f, 0x06, 0xa8, 0x0f, 0xcd, 0x63, 0xf8, 0xf3, 0x4f, 0x58, 0x0a, 0xc5, 0xf5, 0x92, 0x56,
0xcc, 0x15, 0xe5, 0x0d, 0xe4, 0x82, 0x45, 0xc3, 0xa8, 0xf6, 0xdd, 0x41, 0x63, 0xd3, 0x42, 0x4b,
0x6d, 0x7c, 0x59, 0xc1, 0xfb, 0x00, 0x02, 0x62, 0x3c, 0x8c, 0x5b, 0x53, 0xb4, 0x71, 0x0c, 0xe7,
0x21, 0x89, 0x81, 0x27, 0x68, 0x5e, 0xa1, 0x72, 0xb4, 0x3f, 0x5c, 0x91, 0xd8, 0xdc, 0x0b, 0xc9,
0xac, 0xbd, 0x2e, 0xac, 0xa3, 0xbe, 0x9c, 0xa8, 0xcd, 0x28, 0x3e, 0x0c, 0x3e, 0x97, 0x80, 0xd2,
0xe2, 0x8f, 0xfb, 0x1b, 0xac, 0xf4, 0x02, 0x3f, 0x86, 0x08, 0x2d, 0xce, 0xde, 0xf7, 0xf8, 0x1d,
0xcb, 0x3d, 0xb5, 0xac, 0xae, 0x33, 0x51, 0x55, 0x73, 0xc7, 0xc6, 0x12, 0x33, 0x8f, 0x84, 0xce,
0x66, 0xbe, 0x58, 0x3c, 0xa1, 0xff, 0x6e, 0xfd, 0x9f, 0xde, 0xc2, 0x5b, 0x5b, 0xb4, 0xb0, 0x96,
0xb4, 0x63, 0x61, 0xdd, 0xa9, 0x44, 0x5b, 0x22, 0x3a, 0xf2, 0xc9, 0xc0, 0x54, 0x9a, 0xcf, 0x25,
0xfa, 0x96, 0x04, 0xe6, 0xc8, 0x57, 0xe0, 0x51, 0x39, 0x73, 0x9a, 0x59, 0xc7, 0x8c, 0xa3, 0xbb,
0xe2, 0xde, 0xf1, 0xf1, 0xff, 0xff, 0xae, 0xd3, 0x37, 0xf6, 0x97, 0xb0, 0x8a, 0x72, 0xae, 0x66,
0x36, 0xfb, 0xbf, 0xda, 0xb8, 0xf3, 0xdf, 0xec, 0xec, 0xdf, 0x00, 0xf3, 0xeb, 0x29, 0x79, 0x19,
0xfd, 0x6f, 0xbc, 0xf1, 0xf0, 0xd1, 0xe6, 0xa3, 0x3b, 0x1d, 0xd2, 0x28, 0xeb, 0x36, 0x66, 0x34,
0xd6, 0xfc, 0x14, 0x38, 0x73, 0x2c, 0xb5, 0x0b, 0x94, 0x0e, 0x67, 0xc2, 0xa5, 0x1d, 0x6a, 0x1a,
0xc4, 0x39, 0x29, 0x7d, 0xdb, 0x4d, 0x1b, 0x9e, 0x8b, 0x05, 0x34, 0x5d, 0xca, 0x09, 0x17, 0xb6,
0x96, 0xec, 0xf4, 0xa0, 0x5f, 0x8b, 0x06, 0xf6, 0xe3, 0x89, 0x1f, 0xb4, 0xdc, 0x0e, 0x5e, 0xbd,
0x7a, 0x07, 0xfd, 0x6a, 0x6b, 0xbb, 0x84, 0x1c, 0x3a, 0xc5, 0x60, 0xcc, 0x2c, 0x1e, 0x80, 0xc2,
0x25, 0x3c, 0xb8, 0x7b, 0x3d, 0x22, 0x94, 0x24, 0xcd, 0x70, 0x3a, 0xa1, 0x55, 0x4c, 0x6b, 0xe6,
0xca, 0xb0, 0x83, 0xd4, 0x4a, 0x51, 0x60, 0xb4, 0x96, 0x40, 0xba, 0x1e, 0x27, 0x9d, 0x67, 0xcb,
0xe5, 0x01, 0x90, 0x6c, 0x2e, 0x48, 0x2b, 0xbb, 0x3c, 0x5c, 0x69, 0x0f, 0x3e, 0x23, 0xeb, 0x00,
0xdb, 0x09, 0xf2, 0xd1, 0xde, 0x0d, 0x57, 0x31, 0x37, 0xc6, 0xff, 0xef, 0x35, 0x29, 0x7a, 0x7c,
0xf3, 0x7e, 0xd0, 0x7a, 0xdf, 0xdb, 0x46, 0x57, 0xc2, 0x22, 0x65, 0x52, 0x46, 0xcf, 0xba, 0x58,
0xa2, 0x0a, 0x0f, 0x40, 0xf4, 0xc3, 0x84, 0xc7, 0xc9, 0xc7, 0x8e, 0x3f, 0x48, 0x4b, 0xdc, 0x7a,
0xbd, 0x88, 0xc3, 0x0a, 0xab, 0x28, 0x7a, 0xe6, 0xfb, 0x95, 0x80, 0xb7, 0x7a, 0x11, 0x43, 0x7e,
0xf4, 0xae, 0x67, 0x5e, 0x4a, 0x9b, 0x98, 0x91, 0x57, 0x25, 0x7d, 0x99, 0xf1, 0x61, 0xd7, 0x84,
0xf6, 0x10, 0x56, 0xe3, 0xa3, 0xdd, 0xf0, 0x67, 0x4f, 0x5e, 0xc3, 0x7c, 0x60, 0xdc, 0x3f, 0xa2,
0x59, 0xfb, 0x98, 0xbe, 0x05, 0x7a, 0xda, 0x17, 0xc7, 0x5d, 0x05, 0x00, 0x00
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xa4, 0x93, 0xe5, 0xb6, 0xe3, 0x20,
0x10, 0x80, 0x7f, 0xf7, 0x3e, 0xc5, 0x5c, 0x56, 0x9a, 0x9c, 0xd3, 0x90, 0x75, 0x6d, 0xee, 0xba,
0xbb, 0xbb, 0x90, 0x30, 0x6d, 0xd8, 0x12, 0xc8, 0x01, 0x6a, 0x57, 0xde, 0x7d, 0x21, 0xb2, 0xee,
0xfb, 0x07, 0x9d, 0xf9, 0xc6, 0xc7, 0x9b, 0x5c, 0x17, 0x6e, 0x5d, 0x23, 0x94, 0xae, 0x92, 0x5b,
0x1b, 0xe3, 0xb0, 0x81, 0x64, 0x6a, 0x9a, 0x11, 0x54, 0x64, 0x6b, 0x63, 0x30, 0x2e, 0x91, 0x71,
0xbf, 0x0f, 0xc6, 0x15, 0x3a, 0x06, 0x45, 0xc9, 0x8c, 0x45, 0x97, 0x91, 0xb9, 0x9b, 0x24, 0xa7,
0x08, 0xa4, 0xcd, 0x97, 0x14, 0x6a, 0x06, 0x06, 0x65, 0x46, 0x44, 0xa1, 0x15, 0x81, 0xd2, 0xe0,
0x24, 0x23, 0x34, 0x9d, 0xb0, 0x45, 0x78, 0xa0, 0x76, 0x31, 0x6d, 0x45, 0x3b, 0x8a, 0x62, 0x15,
0x66, 0x64, 0x21, 0x70, 0x59, 0x6b, 0xe3, 0x08, 0x78, 0x19, 0x87, 0xca, 0x53, 0x97, 0x82, 0xbb,
0x32, 0xe3, 0xe8, 0xd5, 0x30, 0x69, 0x2e, 0x23, 0x10, 0x4a, 0x38, 0xc1, 0x64, 0x62, 0x0b, 0x26,
0x31, 0x3b, 0xdc, 0x83, 0x6c, 0x61, 0x44, 0xed, 0xc2, 0x71, 0x90, 0xa6, 0x70, 0x4f, 0x41, 0xcd,
0xa6, 0x08, 0x52, 0x33, 0x0e, 0xda, 0xc0, 0xb2, 0x44, 0x15, 0x9c, 0x55, 0x53, 0xa1, 0xa6, 0xe0,
0x4a, 0xac, 0xd0, 0x8e, 0x20, 0x47, 0xeb, 0xc0, 0x69, 0x60, 0x9c, 0x7b, 0xac, 0xf7, 0x1a, 0xfd,
0x06, 0xef, 0x43, 0x88, 0xef, 0x9b, 0xf7, 0x85, 0x16, 0x1c, 0xae, 0xde, 0x7b, 0x72, 0x29, 0x60,
0xc5, 0x04, 0x22, 0xa9, 0xbd, 0xd5, 0x47, 0x4e, 0x1b, 0x0f, 0xa7, 0x0d, 0x06, 0xb2, 0x2c, 0x83,
0x21, 0x67, 0x66, 0x36, 0x84, 0xdd, 0x5d, 0x88, 0x36, 0xa3, 0x61, 0xf3, 0x3e, 0x0c, 0xa8, 0x2f,
0xc5, 0x63, 0x38, 0x78, 0x10, 0x96, 0x42, 0x71, 0xbd, 0xa4, 0x15, 0x73, 0x45, 0x79, 0x07, 0xb9,
0x60, 0xd1, 0x30, 0xaa, 0x7d, 0x76, 0xd0, 0xd8, 0xa4, 0xd0, 0x52, 0x1b, 0x1f, 0x56, 0xd0, 0x3e,
0x03, 0x81, 0x18, 0x0f, 0xe3, 0x56, 0x14, 0x6d, 0x1c, 0xc3, 0x4e, 0x70, 0x62, 0xe0, 0x0b, 0x34,
0xaf, 0x50, 0x39, 0xda, 0x1f, 0xae, 0x48, 0x6c, 0xee, 0x85, 0x64, 0xd6, 0xde, 0x16, 0xd6, 0x51,
0x1f, 0x4e, 0xd4, 0x7a, 0x14, 0x9f, 0x0d, 0x3a, 0x7b, 0x80, 0xd2, 0xe2, 0x9f, 0xeb, 0x1b, 0xac,
0xf4, 0x02, 0xbf, 0x46, 0x84, 0x14, 0xa7, 0x9f, 0x73, 0xdc, 0x57, 0xf9, 0x53, 0x69, 0x59, 0x5d,
0xa7, 0xa2, 0xaa, 0xe6, 0x8e, 0xe5, 0x12, 0x53, 0x4f, 0x42, 0x67, 0x53, 0x1f, 0x2c, 0xae, 0xe8,
0xa5, 0xd3, 0xeb, 0xe7, 0x37, 0xef, 0xe4, 0x47, 0x69, 0x61, 0x2d, 0x69, 0xdb, 0xc2, 0xba, 0xb5,
0x44, 0x5b, 0x22, 0x3a, 0xf2, 0x4d, 0xc3, 0x54, 0x9a, 0xcf, 0x25, 0xfa, 0x94, 0x84, 0xca, 0x91,
0x9f, 0xe0, 0x51, 0x39, 0xb3, 0x4e, 0xad, 0x63, 0xc6, 0xd1, 0x8b, 0x0f, 0x9f, 0x95, 0xd5, 0x8b,
0xd3, 0xb7, 0xe8, 0x07, 0xfb, 0x4f, 0xac, 0xa2, 0x9c, 0xab, 0x99, 0x4d, 0x2f, 0x6e, 0x5f, 0x99,
0xdc, 0x49, 0xd6, 0x2b, 0x8f, 0xf9, 0x0f, 0x97, 0xfc, 0x1b, 0xbd, 0x78, 0xf3, 0x9e, 0xcd, 0xcd,
0xe5, 0xbc, 0x23, 0x8d, 0xd3, 0x6e, 0x62, 0xc6, 0xb9, 0xe6, 0x6b, 0xe0, 0xcc, 0xb1, 0xc4, 0x2e,
0x50, 0x3a, 0x9c, 0x09, 0x97, 0x74, 0xd4, 0x24, 0x3c, 0x67, 0xa4, 0xf4, 0x69, 0x37, 0xad, 0x79,
0x2e, 0x16, 0xd0, 0x64, 0x29, 0x23, 0x5c, 0xd8, 0x5a, 0xb2, 0xf5, 0x99, 0x7e, 0x2c, 0x1a, 0xec,
0xd7, 0x1d, 0x3f, 0x68, 0x6b, 0x3b, 0x78, 0xf7, 0xee, 0x13, 0xfa, 0xdd, 0xb1, 0xe3, 0x25, 0x64,
0xd0, 0x7d, 0x0c, 0x72, 0x66, 0x7d, 0x53, 0x29, 0x5c, 0xc2, 0x93, 0x87, 0xb7, 0x23, 0x42, 0xc9,
0xa8, 0x69, 0x4e, 0x27, 0xb4, 0x8a, 0x69, 0xcd, 0x5c, 0x19, 0x66, 0x90, 0x5a, 0x29, 0x0a, 0x8c,
0x0e, 0x8d, 0x20, 0x39, 0x1c, 0xb7, 0x8a, 0x7b, 0x67, 0x37, 0xda, 0x83, 0x37, 0x6e, 0x1d, 0x60,
0xdb, 0x2c, 0x1e, 0xfc, 0xa9, 0x8f, 0x8a, 0xb9, 0x31, 0x7e, 0x7f, 0xd4, 0x78, 0xe3, 0x51, 0xe6,
0x73, 0x4f, 0xf5, 0xba, 0xf7, 0x8d, 0xae, 0x84, 0x45, 0xca, 0xa4, 0x8c, 0x5e, 0x75, 0x0e, 0x89,
0x2a, 0xcc, 0x7a, 0xf4, 0xc7, 0xb5, 0x8d, 0x47, 0x5f, 0x2b, 0xfe, 0x61, 0x05, 0xba, 0x30, 0xde,
0xc4, 0x61, 0x5a, 0x55, 0x14, 0xbd, 0xf2, 0xa9, 0x19, 0x81, 0x97, 0x7a, 0x13, 0x43, 0xb6, 0xf5,
0x29, 0x3d, 0xfe, 0x95, 0x36, 0x36, 0x23, 0xff, 0x35, 0xea, 0xc3, 0x8c, 0xcf, 0x76, 0x49, 0x08,
0x87, 0x6e, 0x0a, 0x3e, 0x0e, 0x29, 0x1b, 0x80, 0xd8, 0xc0, 0x78, 0x02, 0x47, 0x32, 0x28, 0x72,
0x81, 0xe5, 0xa5, 0x3e, 0xa4, 0xdc, 0x04, 0x00, 0x12, 0x28, 0x85, 0xf3, 0x48, 0x05, 0x00, 0x00
};
inline void serveFingerprintsHtml(AsyncWebServerRequest* request) {
@ -115,51 +113,50 @@ inline void serveFingerprintsHtml(AsyncWebServerRequest* request) {
}
// index.html
const uint16_t INDEX_HTML_L = 685;
const uint16_t INDEX_HTML_L = 672;
const uint8_t INDEX_HTML[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x9d, 0x54, 0xc7, 0x96, 0xe3, 0x2a,
0x10, 0x5d, 0xbb, 0xbf, 0xa2, 0x9a, 0x17, 0x2c, 0x9d, 0x23, 0xa1, 0xce, 0xd1, 0xea, 0x17, 0x67,
0x36, 0x93, 0x73, 0x0e, 0x58, 0x94, 0x2d, 0xc6, 0x08, 0xd4, 0x80, 0xed, 0x8e, 0xff, 0x3e, 0xa0,
0x30, 0x39, 0x6f, 0x24, 0xa8, 0x70, 0x2b, 0xdc, 0x2a, 0x46, 0xab, 0x5c, 0x17, 0xee, 0xb4, 0x46,
0x28, 0x5d, 0x25, 0x8f, 0x56, 0x46, 0xe1, 0x07, 0x92, 0xa9, 0x69, 0x4e, 0x50, 0x91, 0xa3, 0x95,
0xc1, 0xa8, 0x44, 0xc6, 0xfd, 0x7f, 0x30, 0xaa, 0xd0, 0x31, 0x28, 0x4a, 0x66, 0x2c, 0xba, 0x9c,
0xcc, 0xdd, 0x24, 0xdd, 0x23, 0x90, 0x35, 0x2a, 0x29, 0xd4, 0x0c, 0x0c, 0xca, 0x9c, 0x88, 0x42,
0x2b, 0x02, 0xa5, 0xc1, 0x49, 0x4e, 0x68, 0x36, 0x61, 0x8b, 0x20, 0xa0, 0x76, 0x31, 0x0d, 0xa6,
0xef, 0x50, 0x14, 0xab, 0x30, 0x27, 0x0b, 0x81, 0xcb, 0x5a, 0x1b, 0x47, 0xc0, 0xdb, 0x38, 0x54,
0x1e, 0x75, 0x29, 0xb8, 0x2b, 0x73, 0x8e, 0xde, 0x0d, 0xd3, 0xe6, 0x92, 0x80, 0x50, 0xc2, 0x09,
0x26, 0x53, 0x5b, 0x30, 0x89, 0xf9, 0x7a, 0x0f, 0x64, 0x0b, 0x23, 0x6a, 0x17, 0x8e, 0x83, 0x2c,
0x83, 0x5b, 0x0a, 0x6a, 0x36, 0x45, 0x90, 0x9a, 0x71, 0xd0, 0x06, 0x96, 0x25, 0xaa, 0x90, 0xac,
0x9a, 0x0a, 0x35, 0x05, 0x57, 0x62, 0x85, 0x36, 0x81, 0x31, 0x5a, 0x07, 0x4e, 0x03, 0xe3, 0xdc,
0xc3, 0xfa, 0xac, 0xd1, 0xff, 0xe0, 0x75, 0x28, 0xf1, 0x75, 0x23, 0x5f, 0x68, 0xc1, 0xe1, 0xea,
0xad, 0x07, 0xff, 0x05, 0x58, 0x31, 0x81, 0x48, 0x6a, 0x1f, 0xf5, 0x9e, 0xd3, 0xc6, 0x83, 0xd3,
0x06, 0x06, 0xf2, 0x3c, 0x87, 0x21, 0x67, 0x66, 0x36, 0x84, 0x8b, 0x0b, 0x88, 0x56, 0xa3, 0x61,
0x23, 0x1f, 0x06, 0xa8, 0x0f, 0xcd, 0x63, 0xf8, 0xf3, 0x4f, 0x58, 0x0a, 0xc5, 0xf5, 0x92, 0x56,
0xcc, 0x15, 0xe5, 0x0d, 0xe4, 0x82, 0x45, 0xc3, 0xa8, 0xf6, 0xdd, 0x41, 0x63, 0xd3, 0x42, 0x4b,
0x6d, 0x7c, 0x59, 0xc1, 0xfb, 0x00, 0x02, 0x62, 0x3c, 0x8c, 0x5b, 0x53, 0xb4, 0x71, 0x0c, 0xe7,
0x21, 0x89, 0x81, 0x27, 0x68, 0x5e, 0xa1, 0x72, 0xb4, 0x3f, 0x5c, 0x91, 0xd8, 0xdc, 0x0b, 0xc9,
0xac, 0xbd, 0x2e, 0xac, 0xa3, 0xbe, 0x9c, 0xa8, 0xcd, 0x28, 0x3e, 0x0c, 0x3e, 0x97, 0x80, 0xd2,
0xe2, 0x8f, 0xfb, 0x1b, 0xac, 0xf4, 0x02, 0x3f, 0x86, 0x08, 0x2d, 0xce, 0xde, 0xf7, 0xf8, 0x1d,
0xcb, 0x3d, 0xb5, 0xac, 0xae, 0x33, 0x51, 0x55, 0x73, 0xc7, 0xc6, 0x12, 0x33, 0x8f, 0x84, 0xce,
0x66, 0xbe, 0x58, 0x3c, 0xa1, 0xff, 0x6e, 0xfd, 0x9f, 0xde, 0xc2, 0x5b, 0x5b, 0xb4, 0xb0, 0x96,
0xb4, 0x63, 0x61, 0xdd, 0xa9, 0x44, 0x5b, 0x22, 0x3a, 0xf2, 0xc9, 0xc0, 0x54, 0x9a, 0xcf, 0x25,
0xfa, 0x96, 0x04, 0xe6, 0xc8, 0x57, 0xe0, 0x51, 0x39, 0x73, 0x9a, 0x59, 0xc7, 0x8c, 0xa3, 0xbb,
0xe2, 0xde, 0xf1, 0xf1, 0xff, 0xff, 0xae, 0xd3, 0x37, 0xf6, 0x97, 0xb0, 0x8a, 0x72, 0xae, 0x66,
0x36, 0xfb, 0xbf, 0xda, 0xb8, 0xf3, 0xdf, 0xec, 0xec, 0xdf, 0x00, 0xf3, 0xeb, 0x29, 0x79, 0x19,
0xfd, 0x6f, 0xbc, 0xf1, 0xf0, 0xd1, 0xe6, 0xa3, 0x3b, 0x1d, 0xd2, 0x28, 0xeb, 0x36, 0x66, 0x34,
0xd6, 0xfc, 0x14, 0x38, 0x73, 0x2c, 0xb5, 0x0b, 0x94, 0x0e, 0x67, 0xc2, 0xa5, 0x1d, 0x6a, 0x1a,
0xc4, 0x39, 0x29, 0x7d, 0xdb, 0x4d, 0x1b, 0x9e, 0x8b, 0x05, 0x34, 0x5d, 0xca, 0x09, 0x17, 0xb6,
0x96, 0xec, 0xf4, 0xa0, 0x5f, 0x8b, 0x06, 0xf6, 0xe3, 0x89, 0x1f, 0xb4, 0xdc, 0x0e, 0x5e, 0xbd,
0x7a, 0x07, 0xfd, 0x6a, 0x6b, 0xbb, 0x84, 0x1c, 0x3a, 0xc5, 0x60, 0xcc, 0x2c, 0x1e, 0x80, 0xc2,
0x25, 0x3c, 0xb8, 0x7b, 0x3d, 0x22, 0x94, 0x24, 0xcd, 0x70, 0x3a, 0xa1, 0x55, 0x4c, 0x6b, 0xe6,
0xca, 0xb0, 0x83, 0xd4, 0x4a, 0x51, 0x60, 0xb4, 0x96, 0x40, 0xba, 0x1e, 0x27, 0x9d, 0x67, 0xcb,
0xe5, 0x01, 0x90, 0x6c, 0x2e, 0x48, 0x2b, 0xbb, 0x3c, 0x5c, 0x69, 0x0f, 0x3e, 0x23, 0xeb, 0x00,
0xdb, 0x09, 0xf2, 0xd1, 0xde, 0x0d, 0x57, 0x31, 0x37, 0xc6, 0xff, 0xef, 0x35, 0x29, 0x7a, 0x7c,
0xf3, 0x7e, 0xd0, 0x7a, 0xdf, 0xdb, 0x46, 0x57, 0xc2, 0x22, 0x65, 0x52, 0x46, 0xcf, 0xba, 0x58,
0xa2, 0x0a, 0x0f, 0x40, 0xf4, 0xc3, 0x84, 0xc7, 0xc9, 0xc7, 0x8e, 0x3f, 0x48, 0x4b, 0xdc, 0x7a,
0xbd, 0x88, 0xc3, 0x0a, 0xab, 0x28, 0x7a, 0xe6, 0xfb, 0x95, 0x80, 0xb7, 0x7a, 0x11, 0x43, 0x7e,
0xf4, 0xae, 0x67, 0x5e, 0x4a, 0x9b, 0x98, 0x91, 0x57, 0x25, 0x7d, 0x99, 0xf1, 0x61, 0xd7, 0x84,
0xf6, 0x10, 0x56, 0xe3, 0xa3, 0xdd, 0xf0, 0x67, 0x4f, 0x5e, 0xc3, 0x7c, 0x60, 0xdc, 0x3f, 0xa2,
0x59, 0xfb, 0x98, 0xbe, 0x05, 0x7a, 0xda, 0x17, 0xc7, 0x5d, 0x05, 0x00, 0x00
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xa4, 0x93, 0xe5, 0xb6, 0xe3, 0x20,
0x10, 0x80, 0x7f, 0xf7, 0x3e, 0xc5, 0x5c, 0x56, 0x9a, 0x9c, 0xd3, 0x90, 0x75, 0x6d, 0xee, 0xba,
0xbb, 0xbb, 0x90, 0x30, 0x6d, 0xd8, 0x12, 0xc8, 0x01, 0x6a, 0x57, 0xde, 0x7d, 0x21, 0xb2, 0xee,
0xfb, 0x07, 0x9d, 0xf9, 0xc6, 0xc7, 0x9b, 0x5c, 0x17, 0x6e, 0x5d, 0x23, 0x94, 0xae, 0x92, 0x5b,
0x1b, 0xe3, 0xb0, 0x81, 0x64, 0x6a, 0x9a, 0x11, 0x54, 0x64, 0x6b, 0x63, 0x30, 0x2e, 0x91, 0x71,
0xbf, 0x0f, 0xc6, 0x15, 0x3a, 0x06, 0x45, 0xc9, 0x8c, 0x45, 0x97, 0x91, 0xb9, 0x9b, 0x24, 0xa7,
0x08, 0xa4, 0xcd, 0x97, 0x14, 0x6a, 0x06, 0x06, 0x65, 0x46, 0x44, 0xa1, 0x15, 0x81, 0xd2, 0xe0,
0x24, 0x23, 0x34, 0x9d, 0xb0, 0x45, 0x78, 0xa0, 0x76, 0x31, 0x6d, 0x45, 0x3b, 0x8a, 0x62, 0x15,
0x66, 0x64, 0x21, 0x70, 0x59, 0x6b, 0xe3, 0x08, 0x78, 0x19, 0x87, 0xca, 0x53, 0x97, 0x82, 0xbb,
0x32, 0xe3, 0xe8, 0xd5, 0x30, 0x69, 0x2e, 0x23, 0x10, 0x4a, 0x38, 0xc1, 0x64, 0x62, 0x0b, 0x26,
0x31, 0x3b, 0xdc, 0x83, 0x6c, 0x61, 0x44, 0xed, 0xc2, 0x71, 0x90, 0xa6, 0x70, 0x4f, 0x41, 0xcd,
0xa6, 0x08, 0x52, 0x33, 0x0e, 0xda, 0xc0, 0xb2, 0x44, 0x15, 0x9c, 0x55, 0x53, 0xa1, 0xa6, 0xe0,
0x4a, 0xac, 0xd0, 0x8e, 0x20, 0x47, 0xeb, 0xc0, 0x69, 0x60, 0x9c, 0x7b, 0xac, 0xf7, 0x1a, 0xfd,
0x06, 0xef, 0x43, 0x88, 0xef, 0x9b, 0xf7, 0x85, 0x16, 0x1c, 0xae, 0xde, 0x7b, 0x72, 0x29, 0x60,
0xc5, 0x04, 0x22, 0xa9, 0xbd, 0xd5, 0x47, 0x4e, 0x1b, 0x0f, 0xa7, 0x0d, 0x06, 0xb2, 0x2c, 0x83,
0x21, 0x67, 0x66, 0x36, 0x84, 0xdd, 0x5d, 0x88, 0x36, 0xa3, 0x61, 0xf3, 0x3e, 0x0c, 0xa8, 0x2f,
0xc5, 0x63, 0x38, 0x78, 0x10, 0x96, 0x42, 0x71, 0xbd, 0xa4, 0x15, 0x73, 0x45, 0x79, 0x07, 0xb9,
0x60, 0xd1, 0x30, 0xaa, 0x7d, 0x76, 0xd0, 0xd8, 0xa4, 0xd0, 0x52, 0x1b, 0x1f, 0x56, 0xd0, 0x3e,
0x03, 0x81, 0x18, 0x0f, 0xe3, 0x56, 0x14, 0x6d, 0x1c, 0xc3, 0x4e, 0x70, 0x62, 0xe0, 0x0b, 0x34,
0xaf, 0x50, 0x39, 0xda, 0x1f, 0xae, 0x48, 0x6c, 0xee, 0x85, 0x64, 0xd6, 0xde, 0x16, 0xd6, 0x51,
0x1f, 0x4e, 0xd4, 0x7a, 0x14, 0x9f, 0x0d, 0x3a, 0x7b, 0x80, 0xd2, 0xe2, 0x9f, 0xeb, 0x1b, 0xac,
0xf4, 0x02, 0xbf, 0x46, 0x84, 0x14, 0xa7, 0x9f, 0x73, 0xdc, 0x57, 0xf9, 0x53, 0x69, 0x59, 0x5d,
0xa7, 0xa2, 0xaa, 0xe6, 0x8e, 0xe5, 0x12, 0x53, 0x4f, 0x42, 0x67, 0x53, 0x1f, 0x2c, 0xae, 0xe8,
0xa5, 0xd3, 0xeb, 0xe7, 0x37, 0xef, 0xe4, 0x47, 0x69, 0x61, 0x2d, 0x69, 0xdb, 0xc2, 0xba, 0xb5,
0x44, 0x5b, 0x22, 0x3a, 0xf2, 0x4d, 0xc3, 0x54, 0x9a, 0xcf, 0x25, 0xfa, 0x94, 0x84, 0xca, 0x91,
0x9f, 0xe0, 0x51, 0x39, 0xb3, 0x4e, 0xad, 0x63, 0xc6, 0xd1, 0x8b, 0x0f, 0x9f, 0x95, 0xd5, 0x8b,
0xd3, 0xb7, 0xe8, 0x07, 0xfb, 0x4f, 0xac, 0xa2, 0x9c, 0xab, 0x99, 0x4d, 0x2f, 0x6e, 0x5f, 0x99,
0xdc, 0x49, 0xd6, 0x2b, 0x8f, 0xf9, 0x0f, 0x97, 0xfc, 0x1b, 0xbd, 0x78, 0xf3, 0x9e, 0xcd, 0xcd,
0xe5, 0xbc, 0x23, 0x8d, 0xd3, 0x6e, 0x62, 0xc6, 0xb9, 0xe6, 0x6b, 0xe0, 0xcc, 0xb1, 0xc4, 0x2e,
0x50, 0x3a, 0x9c, 0x09, 0x97, 0x74, 0xd4, 0x24, 0x3c, 0x67, 0xa4, 0xf4, 0x69, 0x37, 0xad, 0x79,
0x2e, 0x16, 0xd0, 0x64, 0x29, 0x23, 0x5c, 0xd8, 0x5a, 0xb2, 0xf5, 0x99, 0x7e, 0x2c, 0x1a, 0xec,
0xd7, 0x1d, 0x3f, 0x68, 0x6b, 0x3b, 0x78, 0xf7, 0xee, 0x13, 0xfa, 0xdd, 0xb1, 0xe3, 0x25, 0x64,
0xd0, 0x7d, 0x0c, 0x72, 0x66, 0x7d, 0x53, 0x29, 0x5c, 0xc2, 0x93, 0x87, 0xb7, 0x23, 0x42, 0xc9,
0xa8, 0x69, 0x4e, 0x27, 0xb4, 0x8a, 0x69, 0xcd, 0x5c, 0x19, 0x66, 0x90, 0x5a, 0x29, 0x0a, 0x8c,
0x0e, 0x8d, 0x20, 0x39, 0x1c, 0xb7, 0x8a, 0x7b, 0x67, 0x37, 0xda, 0x83, 0x37, 0x6e, 0x1d, 0x60,
0xdb, 0x2c, 0x1e, 0xfc, 0xa9, 0x8f, 0x8a, 0xb9, 0x31, 0x7e, 0x7f, 0xd4, 0x78, 0xe3, 0x51, 0xe6,
0x73, 0x4f, 0xf5, 0xba, 0xf7, 0x8d, 0xae, 0x84, 0x45, 0xca, 0xa4, 0x8c, 0x5e, 0x75, 0x0e, 0x89,
0x2a, 0xcc, 0x7a, 0xf4, 0xc7, 0xb5, 0x8d, 0x47, 0x5f, 0x2b, 0xfe, 0x61, 0x05, 0xba, 0x30, 0xde,
0xc4, 0x61, 0x5a, 0x55, 0x14, 0xbd, 0xf2, 0xa9, 0x19, 0x81, 0x97, 0x7a, 0x13, 0x43, 0xb6, 0xf5,
0x29, 0x3d, 0xfe, 0x95, 0x36, 0x36, 0x23, 0xff, 0x35, 0xea, 0xc3, 0x8c, 0xcf, 0x76, 0x49, 0x08,
0x87, 0x6e, 0x0a, 0x3e, 0x0e, 0x29, 0x1b, 0x80, 0xd8, 0xc0, 0x78, 0x02, 0x47, 0x32, 0x28, 0x72,
0x81, 0xe5, 0xa5, 0x3e, 0xa4, 0xdc, 0x04, 0x00, 0x12, 0x28, 0x85, 0xf3, 0x48, 0x05, 0x00, 0x00
};
inline void serveIndexHtml(AsyncWebServerRequest* request) {
@ -168,52 +165,104 @@ inline void serveIndexHtml(AsyncWebServerRequest* request) {
request->send(response);
}
// network.html
const uint16_t NETWORK_HTML_L = 672;
const uint8_t NETWORK_HTML[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xa4, 0x93, 0xe5, 0xb6, 0xe3, 0x20,
0x10, 0x80, 0x7f, 0xf7, 0x3e, 0xc5, 0x5c, 0x56, 0x9a, 0x9c, 0xd3, 0x90, 0x75, 0x6d, 0xee, 0xba,
0xbb, 0xbb, 0x90, 0x30, 0x6d, 0xd8, 0x12, 0xc8, 0x01, 0x6a, 0x57, 0xde, 0x7d, 0x21, 0xb2, 0xee,
0xfb, 0x07, 0x9d, 0xf9, 0xc6, 0xc7, 0x9b, 0x5c, 0x17, 0x6e, 0x5d, 0x23, 0x94, 0xae, 0x92, 0x5b,
0x1b, 0xe3, 0xb0, 0x81, 0x64, 0x6a, 0x9a, 0x11, 0x54, 0x64, 0x6b, 0x63, 0x30, 0x2e, 0x91, 0x71,
0xbf, 0x0f, 0xc6, 0x15, 0x3a, 0x06, 0x45, 0xc9, 0x8c, 0x45, 0x97, 0x91, 0xb9, 0x9b, 0x24, 0xa7,
0x08, 0xa4, 0xcd, 0x97, 0x14, 0x6a, 0x06, 0x06, 0x65, 0x46, 0x44, 0xa1, 0x15, 0x81, 0xd2, 0xe0,
0x24, 0x23, 0x34, 0x9d, 0xb0, 0x45, 0x78, 0xa0, 0x76, 0x31, 0x6d, 0x45, 0x3b, 0x8a, 0x62, 0x15,
0x66, 0x64, 0x21, 0x70, 0x59, 0x6b, 0xe3, 0x08, 0x78, 0x19, 0x87, 0xca, 0x53, 0x97, 0x82, 0xbb,
0x32, 0xe3, 0xe8, 0xd5, 0x30, 0x69, 0x2e, 0x23, 0x10, 0x4a, 0x38, 0xc1, 0x64, 0x62, 0x0b, 0x26,
0x31, 0x3b, 0xdc, 0x83, 0x6c, 0x61, 0x44, 0xed, 0xc2, 0x71, 0x90, 0xa6, 0x70, 0x4f, 0x41, 0xcd,
0xa6, 0x08, 0x52, 0x33, 0x0e, 0xda, 0xc0, 0xb2, 0x44, 0x15, 0x9c, 0x55, 0x53, 0xa1, 0xa6, 0xe0,
0x4a, 0xac, 0xd0, 0x8e, 0x20, 0x47, 0xeb, 0xc0, 0x69, 0x60, 0x9c, 0x7b, 0xac, 0xf7, 0x1a, 0xfd,
0x06, 0xef, 0x43, 0x88, 0xef, 0x9b, 0xf7, 0x85, 0x16, 0x1c, 0xae, 0xde, 0x7b, 0x72, 0x29, 0x60,
0xc5, 0x04, 0x22, 0xa9, 0xbd, 0xd5, 0x47, 0x4e, 0x1b, 0x0f, 0xa7, 0x0d, 0x06, 0xb2, 0x2c, 0x83,
0x21, 0x67, 0x66, 0x36, 0x84, 0xdd, 0x5d, 0x88, 0x36, 0xa3, 0x61, 0xf3, 0x3e, 0x0c, 0xa8, 0x2f,
0xc5, 0x63, 0x38, 0x78, 0x10, 0x96, 0x42, 0x71, 0xbd, 0xa4, 0x15, 0x73, 0x45, 0x79, 0x07, 0xb9,
0x60, 0xd1, 0x30, 0xaa, 0x7d, 0x76, 0xd0, 0xd8, 0xa4, 0xd0, 0x52, 0x1b, 0x1f, 0x56, 0xd0, 0x3e,
0x03, 0x81, 0x18, 0x0f, 0xe3, 0x56, 0x14, 0x6d, 0x1c, 0xc3, 0x4e, 0x70, 0x62, 0xe0, 0x0b, 0x34,
0xaf, 0x50, 0x39, 0xda, 0x1f, 0xae, 0x48, 0x6c, 0xee, 0x85, 0x64, 0xd6, 0xde, 0x16, 0xd6, 0x51,
0x1f, 0x4e, 0xd4, 0x7a, 0x14, 0x9f, 0x0d, 0x3a, 0x7b, 0x80, 0xd2, 0xe2, 0x9f, 0xeb, 0x1b, 0xac,
0xf4, 0x02, 0xbf, 0x46, 0x84, 0x14, 0xa7, 0x9f, 0x73, 0xdc, 0x57, 0xf9, 0x53, 0x69, 0x59, 0x5d,
0xa7, 0xa2, 0xaa, 0xe6, 0x8e, 0xe5, 0x12, 0x53, 0x4f, 0x42, 0x67, 0x53, 0x1f, 0x2c, 0xae, 0xe8,
0xa5, 0xd3, 0xeb, 0xe7, 0x37, 0xef, 0xe4, 0x47, 0x69, 0x61, 0x2d, 0x69, 0xdb, 0xc2, 0xba, 0xb5,
0x44, 0x5b, 0x22, 0x3a, 0xf2, 0x4d, 0xc3, 0x54, 0x9a, 0xcf, 0x25, 0xfa, 0x94, 0x84, 0xca, 0x91,
0x9f, 0xe0, 0x51, 0x39, 0xb3, 0x4e, 0xad, 0x63, 0xc6, 0xd1, 0x8b, 0x0f, 0x9f, 0x95, 0xd5, 0x8b,
0xd3, 0xb7, 0xe8, 0x07, 0xfb, 0x4f, 0xac, 0xa2, 0x9c, 0xab, 0x99, 0x4d, 0x2f, 0x6e, 0x5f, 0x99,
0xdc, 0x49, 0xd6, 0x2b, 0x8f, 0xf9, 0x0f, 0x97, 0xfc, 0x1b, 0xbd, 0x78, 0xf3, 0x9e, 0xcd, 0xcd,
0xe5, 0xbc, 0x23, 0x8d, 0xd3, 0x6e, 0x62, 0xc6, 0xb9, 0xe6, 0x6b, 0xe0, 0xcc, 0xb1, 0xc4, 0x2e,
0x50, 0x3a, 0x9c, 0x09, 0x97, 0x74, 0xd4, 0x24, 0x3c, 0x67, 0xa4, 0xf4, 0x69, 0x37, 0xad, 0x79,
0x2e, 0x16, 0xd0, 0x64, 0x29, 0x23, 0x5c, 0xd8, 0x5a, 0xb2, 0xf5, 0x99, 0x7e, 0x2c, 0x1a, 0xec,
0xd7, 0x1d, 0x3f, 0x68, 0x6b, 0x3b, 0x78, 0xf7, 0xee, 0x13, 0xfa, 0xdd, 0xb1, 0xe3, 0x25, 0x64,
0xd0, 0x7d, 0x0c, 0x72, 0x66, 0x7d, 0x53, 0x29, 0x5c, 0xc2, 0x93, 0x87, 0xb7, 0x23, 0x42, 0xc9,
0xa8, 0x69, 0x4e, 0x27, 0xb4, 0x8a, 0x69, 0xcd, 0x5c, 0x19, 0x66, 0x90, 0x5a, 0x29, 0x0a, 0x8c,
0x0e, 0x8d, 0x20, 0x39, 0x1c, 0xb7, 0x8a, 0x7b, 0x67, 0x37, 0xda, 0x83, 0x37, 0x6e, 0x1d, 0x60,
0xdb, 0x2c, 0x1e, 0xfc, 0xa9, 0x8f, 0x8a, 0xb9, 0x31, 0x7e, 0x7f, 0xd4, 0x78, 0xe3, 0x51, 0xe6,
0x73, 0x4f, 0xf5, 0xba, 0xf7, 0x8d, 0xae, 0x84, 0x45, 0xca, 0xa4, 0x8c, 0x5e, 0x75, 0x0e, 0x89,
0x2a, 0xcc, 0x7a, 0xf4, 0xc7, 0xb5, 0x8d, 0x47, 0x5f, 0x2b, 0xfe, 0x61, 0x05, 0xba, 0x30, 0xde,
0xc4, 0x61, 0x5a, 0x55, 0x14, 0xbd, 0xf2, 0xa9, 0x19, 0x81, 0x97, 0x7a, 0x13, 0x43, 0xb6, 0xf5,
0x29, 0x3d, 0xfe, 0x95, 0x36, 0x36, 0x23, 0xff, 0x35, 0xea, 0xc3, 0x8c, 0xcf, 0x76, 0x49, 0x08,
0x87, 0x6e, 0x0a, 0x3e, 0x0e, 0x29, 0x1b, 0x80, 0xd8, 0xc0, 0x78, 0x02, 0x47, 0x32, 0x28, 0x72,
0x81, 0xe5, 0xa5, 0x3e, 0xa4, 0xdc, 0x04, 0x00, 0x12, 0x28, 0x85, 0xf3, 0x48, 0x05, 0x00, 0x00
};
inline void serveNetworkHtml(AsyncWebServerRequest* request) {
AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", NETWORK_HTML, NETWORK_HTML_L);
response->addHeader(F("Content-Encoding"), "gzip");
request->send(response);
}
// settings.html
const uint16_t SETTINGS_HTML_L = 685;
const uint16_t SETTINGS_HTML_L = 672;
const uint8_t SETTINGS_HTML[] PROGMEM = {
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x9d, 0x54, 0xc7, 0x96, 0xe3, 0x2a,
0x10, 0x5d, 0xbb, 0xbf, 0xa2, 0x9a, 0x17, 0x2c, 0x9d, 0x23, 0xa1, 0xce, 0xd1, 0xea, 0x17, 0x67,
0x36, 0x93, 0x73, 0x0e, 0x58, 0x94, 0x2d, 0xc6, 0x08, 0xd4, 0x80, 0xed, 0x8e, 0xff, 0x3e, 0xa0,
0x30, 0x39, 0x6f, 0x24, 0xa8, 0x70, 0x2b, 0xdc, 0x2a, 0x46, 0xab, 0x5c, 0x17, 0xee, 0xb4, 0x46,
0x28, 0x5d, 0x25, 0x8f, 0x56, 0x46, 0xe1, 0x07, 0x92, 0xa9, 0x69, 0x4e, 0x50, 0x91, 0xa3, 0x95,
0xc1, 0xa8, 0x44, 0xc6, 0xfd, 0x7f, 0x30, 0xaa, 0xd0, 0x31, 0x28, 0x4a, 0x66, 0x2c, 0xba, 0x9c,
0xcc, 0xdd, 0x24, 0xdd, 0x23, 0x90, 0x35, 0x2a, 0x29, 0xd4, 0x0c, 0x0c, 0xca, 0x9c, 0x88, 0x42,
0x2b, 0x02, 0xa5, 0xc1, 0x49, 0x4e, 0x68, 0x36, 0x61, 0x8b, 0x20, 0xa0, 0x76, 0x31, 0x0d, 0xa6,
0xef, 0x50, 0x14, 0xab, 0x30, 0x27, 0x0b, 0x81, 0xcb, 0x5a, 0x1b, 0x47, 0xc0, 0xdb, 0x38, 0x54,
0x1e, 0x75, 0x29, 0xb8, 0x2b, 0x73, 0x8e, 0xde, 0x0d, 0xd3, 0xe6, 0x92, 0x80, 0x50, 0xc2, 0x09,
0x26, 0x53, 0x5b, 0x30, 0x89, 0xf9, 0x7a, 0x0f, 0x64, 0x0b, 0x23, 0x6a, 0x17, 0x8e, 0x83, 0x2c,
0x83, 0x5b, 0x0a, 0x6a, 0x36, 0x45, 0x90, 0x9a, 0x71, 0xd0, 0x06, 0x96, 0x25, 0xaa, 0x90, 0xac,
0x9a, 0x0a, 0x35, 0x05, 0x57, 0x62, 0x85, 0x36, 0x81, 0x31, 0x5a, 0x07, 0x4e, 0x03, 0xe3, 0xdc,
0xc3, 0xfa, 0xac, 0xd1, 0xff, 0xe0, 0x75, 0x28, 0xf1, 0x75, 0x23, 0x5f, 0x68, 0xc1, 0xe1, 0xea,
0xad, 0x07, 0xff, 0x05, 0x58, 0x31, 0x81, 0x48, 0x6a, 0x1f, 0xf5, 0x9e, 0xd3, 0xc6, 0x83, 0xd3,
0x06, 0x06, 0xf2, 0x3c, 0x87, 0x21, 0x67, 0x66, 0x36, 0x84, 0x8b, 0x0b, 0x88, 0x56, 0xa3, 0x61,
0x23, 0x1f, 0x06, 0xa8, 0x0f, 0xcd, 0x63, 0xf8, 0xf3, 0x4f, 0x58, 0x0a, 0xc5, 0xf5, 0x92, 0x56,
0xcc, 0x15, 0xe5, 0x0d, 0xe4, 0x82, 0x45, 0xc3, 0xa8, 0xf6, 0xdd, 0x41, 0x63, 0xd3, 0x42, 0x4b,
0x6d, 0x7c, 0x59, 0xc1, 0xfb, 0x00, 0x02, 0x62, 0x3c, 0x8c, 0x5b, 0x53, 0xb4, 0x71, 0x0c, 0xe7,
0x21, 0x89, 0x81, 0x27, 0x68, 0x5e, 0xa1, 0x72, 0xb4, 0x3f, 0x5c, 0x91, 0xd8, 0xdc, 0x0b, 0xc9,
0xac, 0xbd, 0x2e, 0xac, 0xa3, 0xbe, 0x9c, 0xa8, 0xcd, 0x28, 0x3e, 0x0c, 0x3e, 0x97, 0x80, 0xd2,
0xe2, 0x8f, 0xfb, 0x1b, 0xac, 0xf4, 0x02, 0x3f, 0x86, 0x08, 0x2d, 0xce, 0xde, 0xf7, 0xf8, 0x1d,
0xcb, 0x3d, 0xb5, 0xac, 0xae, 0x33, 0x51, 0x55, 0x73, 0xc7, 0xc6, 0x12, 0x33, 0x8f, 0x84, 0xce,
0x66, 0xbe, 0x58, 0x3c, 0xa1, 0xff, 0x6e, 0xfd, 0x9f, 0xde, 0xc2, 0x5b, 0x5b, 0xb4, 0xb0, 0x96,
0xb4, 0x63, 0x61, 0xdd, 0xa9, 0x44, 0x5b, 0x22, 0x3a, 0xf2, 0xc9, 0xc0, 0x54, 0x9a, 0xcf, 0x25,
0xfa, 0x96, 0x04, 0xe6, 0xc8, 0x57, 0xe0, 0x51, 0x39, 0x73, 0x9a, 0x59, 0xc7, 0x8c, 0xa3, 0xbb,
0xe2, 0xde, 0xf1, 0xf1, 0xff, 0xff, 0xae, 0xd3, 0x37, 0xf6, 0x97, 0xb0, 0x8a, 0x72, 0xae, 0x66,
0x36, 0xfb, 0xbf, 0xda, 0xb8, 0xf3, 0xdf, 0xec, 0xec, 0xdf, 0x00, 0xf3, 0xeb, 0x29, 0x79, 0x19,
0xfd, 0x6f, 0xbc, 0xf1, 0xf0, 0xd1, 0xe6, 0xa3, 0x3b, 0x1d, 0xd2, 0x28, 0xeb, 0x36, 0x66, 0x34,
0xd6, 0xfc, 0x14, 0x38, 0x73, 0x2c, 0xb5, 0x0b, 0x94, 0x0e, 0x67, 0xc2, 0xa5, 0x1d, 0x6a, 0x1a,
0xc4, 0x39, 0x29, 0x7d, 0xdb, 0x4d, 0x1b, 0x9e, 0x8b, 0x05, 0x34, 0x5d, 0xca, 0x09, 0x17, 0xb6,
0x96, 0xec, 0xf4, 0xa0, 0x5f, 0x8b, 0x06, 0xf6, 0xe3, 0x89, 0x1f, 0xb4, 0xdc, 0x0e, 0x5e, 0xbd,
0x7a, 0x07, 0xfd, 0x6a, 0x6b, 0xbb, 0x84, 0x1c, 0x3a, 0xc5, 0x60, 0xcc, 0x2c, 0x1e, 0x80, 0xc2,
0x25, 0x3c, 0xb8, 0x7b, 0x3d, 0x22, 0x94, 0x24, 0xcd, 0x70, 0x3a, 0xa1, 0x55, 0x4c, 0x6b, 0xe6,
0xca, 0xb0, 0x83, 0xd4, 0x4a, 0x51, 0x60, 0xb4, 0x96, 0x40, 0xba, 0x1e, 0x27, 0x9d, 0x67, 0xcb,
0xe5, 0x01, 0x90, 0x6c, 0x2e, 0x48, 0x2b, 0xbb, 0x3c, 0x5c, 0x69, 0x0f, 0x3e, 0x23, 0xeb, 0x00,
0xdb, 0x09, 0xf2, 0xd1, 0xde, 0x0d, 0x57, 0x31, 0x37, 0xc6, 0xff, 0xef, 0x35, 0x29, 0x7a, 0x7c,
0xf3, 0x7e, 0xd0, 0x7a, 0xdf, 0xdb, 0x46, 0x57, 0xc2, 0x22, 0x65, 0x52, 0x46, 0xcf, 0xba, 0x58,
0xa2, 0x0a, 0x0f, 0x40, 0xf4, 0xc3, 0x84, 0xc7, 0xc9, 0xc7, 0x8e, 0x3f, 0x48, 0x4b, 0xdc, 0x7a,
0xbd, 0x88, 0xc3, 0x0a, 0xab, 0x28, 0x7a, 0xe6, 0xfb, 0x95, 0x80, 0xb7, 0x7a, 0x11, 0x43, 0x7e,
0xf4, 0xae, 0x67, 0x5e, 0x4a, 0x9b, 0x98, 0x91, 0x57, 0x25, 0x7d, 0x99, 0xf1, 0x61, 0xd7, 0x84,
0xf6, 0x10, 0x56, 0xe3, 0xa3, 0xdd, 0xf0, 0x67, 0x4f, 0x5e, 0xc3, 0x7c, 0x60, 0xdc, 0x3f, 0xa2,
0x59, 0xfb, 0x98, 0xbe, 0x05, 0x7a, 0xda, 0x17, 0xc7, 0x5d, 0x05, 0x00, 0x00
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xa4, 0x93, 0xe5, 0xb6, 0xe3, 0x20,
0x10, 0x80, 0x7f, 0xf7, 0x3e, 0xc5, 0x5c, 0x56, 0x9a, 0x9c, 0xd3, 0x90, 0x75, 0x6d, 0xee, 0xba,
0xbb, 0xbb, 0x90, 0x30, 0x6d, 0xd8, 0x12, 0xc8, 0x01, 0x6a, 0x57, 0xde, 0x7d, 0x21, 0xb2, 0xee,
0xfb, 0x07, 0x9d, 0xf9, 0xc6, 0xc7, 0x9b, 0x5c, 0x17, 0x6e, 0x5d, 0x23, 0x94, 0xae, 0x92, 0x5b,
0x1b, 0xe3, 0xb0, 0x81, 0x64, 0x6a, 0x9a, 0x11, 0x54, 0x64, 0x6b, 0x63, 0x30, 0x2e, 0x91, 0x71,
0xbf, 0x0f, 0xc6, 0x15, 0x3a, 0x06, 0x45, 0xc9, 0x8c, 0x45, 0x97, 0x91, 0xb9, 0x9b, 0x24, 0xa7,
0x08, 0xa4, 0xcd, 0x97, 0x14, 0x6a, 0x06, 0x06, 0x65, 0x46, 0x44, 0xa1, 0x15, 0x81, 0xd2, 0xe0,
0x24, 0x23, 0x34, 0x9d, 0xb0, 0x45, 0x78, 0xa0, 0x76, 0x31, 0x6d, 0x45, 0x3b, 0x8a, 0x62, 0x15,
0x66, 0x64, 0x21, 0x70, 0x59, 0x6b, 0xe3, 0x08, 0x78, 0x19, 0x87, 0xca, 0x53, 0x97, 0x82, 0xbb,
0x32, 0xe3, 0xe8, 0xd5, 0x30, 0x69, 0x2e, 0x23, 0x10, 0x4a, 0x38, 0xc1, 0x64, 0x62, 0x0b, 0x26,
0x31, 0x3b, 0xdc, 0x83, 0x6c, 0x61, 0x44, 0xed, 0xc2, 0x71, 0x90, 0xa6, 0x70, 0x4f, 0x41, 0xcd,
0xa6, 0x08, 0x52, 0x33, 0x0e, 0xda, 0xc0, 0xb2, 0x44, 0x15, 0x9c, 0x55, 0x53, 0xa1, 0xa6, 0xe0,
0x4a, 0xac, 0xd0, 0x8e, 0x20, 0x47, 0xeb, 0xc0, 0x69, 0x60, 0x9c, 0x7b, 0xac, 0xf7, 0x1a, 0xfd,
0x06, 0xef, 0x43, 0x88, 0xef, 0x9b, 0xf7, 0x85, 0x16, 0x1c, 0xae, 0xde, 0x7b, 0x72, 0x29, 0x60,
0xc5, 0x04, 0x22, 0xa9, 0xbd, 0xd5, 0x47, 0x4e, 0x1b, 0x0f, 0xa7, 0x0d, 0x06, 0xb2, 0x2c, 0x83,
0x21, 0x67, 0x66, 0x36, 0x84, 0xdd, 0x5d, 0x88, 0x36, 0xa3, 0x61, 0xf3, 0x3e, 0x0c, 0xa8, 0x2f,
0xc5, 0x63, 0x38, 0x78, 0x10, 0x96, 0x42, 0x71, 0xbd, 0xa4, 0x15, 0x73, 0x45, 0x79, 0x07, 0xb9,
0x60, 0xd1, 0x30, 0xaa, 0x7d, 0x76, 0xd0, 0xd8, 0xa4, 0xd0, 0x52, 0x1b, 0x1f, 0x56, 0xd0, 0x3e,
0x03, 0x81, 0x18, 0x0f, 0xe3, 0x56, 0x14, 0x6d, 0x1c, 0xc3, 0x4e, 0x70, 0x62, 0xe0, 0x0b, 0x34,
0xaf, 0x50, 0x39, 0xda, 0x1f, 0xae, 0x48, 0x6c, 0xee, 0x85, 0x64, 0xd6, 0xde, 0x16, 0xd6, 0x51,
0x1f, 0x4e, 0xd4, 0x7a, 0x14, 0x9f, 0x0d, 0x3a, 0x7b, 0x80, 0xd2, 0xe2, 0x9f, 0xeb, 0x1b, 0xac,
0xf4, 0x02, 0xbf, 0x46, 0x84, 0x14, 0xa7, 0x9f, 0x73, 0xdc, 0x57, 0xf9, 0x53, 0x69, 0x59, 0x5d,
0xa7, 0xa2, 0xaa, 0xe6, 0x8e, 0xe5, 0x12, 0x53, 0x4f, 0x42, 0x67, 0x53, 0x1f, 0x2c, 0xae, 0xe8,
0xa5, 0xd3, 0xeb, 0xe7, 0x37, 0xef, 0xe4, 0x47, 0x69, 0x61, 0x2d, 0x69, 0xdb, 0xc2, 0xba, 0xb5,
0x44, 0x5b, 0x22, 0x3a, 0xf2, 0x4d, 0xc3, 0x54, 0x9a, 0xcf, 0x25, 0xfa, 0x94, 0x84, 0xca, 0x91,
0x9f, 0xe0, 0x51, 0x39, 0xb3, 0x4e, 0xad, 0x63, 0xc6, 0xd1, 0x8b, 0x0f, 0x9f, 0x95, 0xd5, 0x8b,
0xd3, 0xb7, 0xe8, 0x07, 0xfb, 0x4f, 0xac, 0xa2, 0x9c, 0xab, 0x99, 0x4d, 0x2f, 0x6e, 0x5f, 0x99,
0xdc, 0x49, 0xd6, 0x2b, 0x8f, 0xf9, 0x0f, 0x97, 0xfc, 0x1b, 0xbd, 0x78, 0xf3, 0x9e, 0xcd, 0xcd,
0xe5, 0xbc, 0x23, 0x8d, 0xd3, 0x6e, 0x62, 0xc6, 0xb9, 0xe6, 0x6b, 0xe0, 0xcc, 0xb1, 0xc4, 0x2e,
0x50, 0x3a, 0x9c, 0x09, 0x97, 0x74, 0xd4, 0x24, 0x3c, 0x67, 0xa4, 0xf4, 0x69, 0x37, 0xad, 0x79,
0x2e, 0x16, 0xd0, 0x64, 0x29, 0x23, 0x5c, 0xd8, 0x5a, 0xb2, 0xf5, 0x99, 0x7e, 0x2c, 0x1a, 0xec,
0xd7, 0x1d, 0x3f, 0x68, 0x6b, 0x3b, 0x78, 0xf7, 0xee, 0x13, 0xfa, 0xdd, 0xb1, 0xe3, 0x25, 0x64,
0xd0, 0x7d, 0x0c, 0x72, 0x66, 0x7d, 0x53, 0x29, 0x5c, 0xc2, 0x93, 0x87, 0xb7, 0x23, 0x42, 0xc9,
0xa8, 0x69, 0x4e, 0x27, 0xb4, 0x8a, 0x69, 0xcd, 0x5c, 0x19, 0x66, 0x90, 0x5a, 0x29, 0x0a, 0x8c,
0x0e, 0x8d, 0x20, 0x39, 0x1c, 0xb7, 0x8a, 0x7b, 0x67, 0x37, 0xda, 0x83, 0x37, 0x6e, 0x1d, 0x60,
0xdb, 0x2c, 0x1e, 0xfc, 0xa9, 0x8f, 0x8a, 0xb9, 0x31, 0x7e, 0x7f, 0xd4, 0x78, 0xe3, 0x51, 0xe6,
0x73, 0x4f, 0xf5, 0xba, 0xf7, 0x8d, 0xae, 0x84, 0x45, 0xca, 0xa4, 0x8c, 0x5e, 0x75, 0x0e, 0x89,
0x2a, 0xcc, 0x7a, 0xf4, 0xc7, 0xb5, 0x8d, 0x47, 0x5f, 0x2b, 0xfe, 0x61, 0x05, 0xba, 0x30, 0xde,
0xc4, 0x61, 0x5a, 0x55, 0x14, 0xbd, 0xf2, 0xa9, 0x19, 0x81, 0x97, 0x7a, 0x13, 0x43, 0xb6, 0xf5,
0x29, 0x3d, 0xfe, 0x95, 0x36, 0x36, 0x23, 0xff, 0x35, 0xea, 0xc3, 0x8c, 0xcf, 0x76, 0x49, 0x08,
0x87, 0x6e, 0x0a, 0x3e, 0x0e, 0x29, 0x1b, 0x80, 0xd8, 0xc0, 0x78, 0x02, 0x47, 0x32, 0x28, 0x72,
0x81, 0xe5, 0xa5, 0x3e, 0xa4, 0xdc, 0x04, 0x00, 0x12, 0x28, 0x85, 0xf3, 0x48, 0x05, 0x00, 0x00
};
inline void serveSettingsHtml(AsyncWebServerRequest* request) {

View File

@ -2,13 +2,13 @@
* Web UI Routes
*
* Compressed Size Summary:
* ui_app_immutable_assets_css: 7,762 bytes
* ui_html: 2,740 bytes
* ui_app_immutable_chunks_js: 41,078 bytes
* ui_app_immutable_assets_css: 8,872 bytes
* ui_html: 3,360 bytes
* ui_app_immutable_chunks_js: 44,332 bytes
* ui_app_immutable_entry_js: 224 bytes
* ui_app_immutable_nodes_js: 418 bytes
* ui_app_immutable_nodes_js: 484 bytes
* ui_svg: 456 bytes
* Total: 52,678 bytes
* Total: 57,728 bytes
*/
#pragma once
@ -22,24 +22,27 @@
#include "ui_svg.h"
inline void setupRoutes(AsyncWebServer* server) {
server->on("/ui/app/immutable/assets/index.Dwd10Ur_.css", HTTP_GET, serveAppImmutableAssetsIndexDwd10UrCss);
server->on("/ui/app/immutable/assets/index.B4D-OeO4.css", HTTP_GET, serveAppImmutableAssetsIndexB4DOeO4Css);
server->on("/ui/app/immutable/chunks/Dm2QCkzB.js", HTTP_GET, serveAppImmutableChunksDm2QCkzBJs);
server->on("/ui/app/immutable/entry/app.Cb2VW3WQ.js", HTTP_GET, serveAppImmutableEntryAppCb2Vw3WqJs);
server->on("/ui/app/immutable/entry/start.7iSqqDB1.js", HTTP_GET, serveAppImmutableEntryStart_7iSqqDb1Js);
server->on("/ui/app/immutable/nodes/0.mRmfOCQ2.js", HTTP_GET, serveAppImmutableNodes_0MRmfOcq2Js);
server->on("/ui/app/immutable/nodes/1.0EiJ79V4.js", HTTP_GET, serveAppImmutableNodes_1_0EiJ79V4Js);
server->on("/ui/app/immutable/nodes/2.Bxme43Dr.js", HTTP_GET, serveAppImmutableNodes_2Bxme43DrJs);
server->on("/ui/app/immutable/nodes/3.CR6EXnD7.js", HTTP_GET, serveAppImmutableNodes_3Cr6EXnD7Js);
server->on("/ui/app/immutable/nodes/4.DrdVjXcz.js", HTTP_GET, serveAppImmutableNodes_4DrdVjXczJs);
server->on("/ui/app/immutable/nodes/5.BXsMqBj-.js", HTTP_GET, serveAppImmutableNodes_5BXsMqBjJs);
server->on("/ui/favicon.svg", HTTP_GET, serveFaviconSvg);
server->on("/app/immutable/assets/index.BvV_u1cj.css", HTTP_GET, serveAppImmutableAssetsIndexBvVU1cjCss);
server->on("/app/immutable/assets/index.C9yXJMb3.css", HTTP_GET, serveAppImmutableAssetsIndexC9yXjMb3Css);
server->on("/app/immutable/chunks/BzEfM-yx.js", HTTP_GET, serveAppImmutableChunksBzEfMYxJs);
server->on("/app/immutable/entry/app.BJOsbrDb.js", HTTP_GET, serveAppImmutableEntryAppBjOsbrDbJs);
server->on("/app/immutable/entry/start.BRWhmY9K.js", HTTP_GET, serveAppImmutableEntryStartBrWhmY9KJs);
server->on("/app/immutable/nodes/0.f-UXSzsA.js", HTTP_GET, serveAppImmutableNodes_0FUxSzsAJs);
server->on("/app/immutable/nodes/1.Qt5HEqQj.js", HTTP_GET, serveAppImmutableNodes_1Qt5HEqQjJs);
server->on("/app/immutable/nodes/2.CAPvpTL7.js", HTTP_GET, serveAppImmutableNodes_2CaPvpTl7Js);
server->on("/app/immutable/nodes/3.BRF1IttE.js", HTTP_GET, serveAppImmutableNodes_3Brf1IttEJs);
server->on("/app/immutable/nodes/4.hR3DFtNr.js", HTTP_GET, serveAppImmutableNodes_4HR3DFtNrJs);
server->on("/app/immutable/nodes/5.B-_jSokT.js", HTTP_GET, serveAppImmutableNodes_5BJSokTJs);
server->on("/app/immutable/nodes/6.pYVBaJC-.js", HTTP_GET, serveAppImmutableNodes_6PYvBaJcJs);
server->on("/favicon.svg", HTTP_GET, serveFaviconSvg);
// HTML routes
server->on("/ui/devices", HTTP_GET, serveDevicesHtml);
server->on("/ui/devices.html", HTTP_GET, serveDevicesHtml);
server->on("/ui/fingerprints", HTTP_GET, serveFingerprintsHtml);
server->on("/ui/fingerprints.html", HTTP_GET, serveFingerprintsHtml);
server->on("/ui/", HTTP_GET, serveIndexHtml);
server->on("/ui/settings", HTTP_GET, serveSettingsHtml);
server->on("/ui/settings.html", HTTP_GET, serveSettingsHtml);
server->on("/devices", HTTP_GET, serveDevicesHtml);
server->on("/devices.html", HTTP_GET, serveDevicesHtml);
server->on("/fingerprints", HTTP_GET, serveFingerprintsHtml);
server->on("/fingerprints.html", HTTP_GET, serveFingerprintsHtml);
server->on("/", HTTP_GET, serveIndexHtml);
server->on("/network", HTTP_GET, serveNetworkHtml);
server->on("/network.html", HTTP_GET, serveNetworkHtml);
server->on("/settings", HTTP_GET, serveSettingsHtml);
server->on("/settings.html", HTTP_GET, serveSettingsHtml);
}

183
ui/package-lock.json generated
View File

@ -17,6 +17,7 @@
"autoprefixer": "^10.4.20",
"change-case": "^5.4.4",
"mime": "^4.0.6",
"nodemon": "^3.1.9",
"postcss": "^8.5.2",
"svelte": "^5.19.9",
"svelte-check": "^4.1.4",
@ -1958,6 +1959,12 @@
"node": ">= 12"
}
},
"node_modules/ignore-by-default": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
"dev": true
},
"node_modules/import-meta-resolve": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
@ -2326,6 +2333,137 @@
"integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
"dev": true
},
"node_modules/nodemon": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
"integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
"dev": true,
"dependencies": {
"chokidar": "^3.5.2",
"debug": "^4",
"ignore-by-default": "^1.0.1",
"minimatch": "^3.1.2",
"pstree.remy": "^1.1.8",
"semver": "^7.5.3",
"simple-update-notifier": "^2.0.0",
"supports-color": "^5.5.0",
"touch": "^3.1.0",
"undefsafe": "^2.0.5"
},
"bin": {
"nodemon": "bin/nodemon.js"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/nodemon"
}
},
"node_modules/nodemon/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/nodemon/node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/nodemon/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/nodemon/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/nodemon/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/nodemon/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/nodemon/node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/nodemon/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@ -2607,6 +2745,12 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
"node_modules/pstree.remy": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
"integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
"dev": true
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -2757,6 +2901,18 @@
"node": ">=6"
}
},
"node_modules/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/set-cookie-parser": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
@ -2796,6 +2952,18 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/simple-update-notifier": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
"integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
"dev": true,
"dependencies": {
"semver": "^7.5.3"
},
"engines": {
"node": ">=10"
}
},
"node_modules/sirv": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz",
@ -3199,6 +3367,15 @@
"node": ">=6"
}
},
"node_modules/touch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
"integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
"dev": true,
"bin": {
"nodetouch": "bin/nodetouch.js"
}
},
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@ -3224,6 +3401,12 @@
"node": ">=14.17"
}
},
"node_modules/undefsafe": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
"dev": true
},
"node_modules/undici-types": {
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",

View File

@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite dev",
"build:watch": "nodemon --watch src --watch svelte.config.js --ext js,ts,svelte,css --exec \"vite build\"",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
@ -21,6 +22,7 @@
"change-case": "^5.4.4",
"mime": "^4.0.6",
"postcss": "^8.5.2",
"nodemon": "^3.1.9",
"svelte": "^5.19.9",
"svelte-check": "^4.1.4",
"svelte-table": "^0.6.3",

View File

@ -5,7 +5,7 @@
<button
class="p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:focus:ring-gray-700"
on:click={() => $darkMode = !$darkMode}
onclick={() => $darkMode = !$darkMode}
aria-label="Toggle dark mode"
>
{#if $darkMode}

View File

@ -0,0 +1,47 @@
<script lang="ts">
import { mobileMenuOpen } from '$lib/stores';
function toggleMenu() {
mobileMenuOpen.update(value => !value);
}
</script>
<button
type="button"
class="md:hidden inline-flex items-center justify-center p-2 rounded-md text-gray-700 hover:text-gray-900 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500 dark:text-gray-200 dark:hover:text-white dark:hover:bg-gray-700"
aria-controls="mobile-menu"
aria-expanded={$mobileMenuOpen}
onclick={toggleMenu}
>
<span class="sr-only">Open main menu</span>
<!-- Icon when menu is closed -->
<svg
class="h-6 w-6 {$mobileMenuOpen ? 'hidden' : 'block'}"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
<!-- Icon when menu is open -->
<svg
class="h-6 w-6 {$mobileMenuOpen ? 'block' : 'hidden'}"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>

View File

@ -50,6 +50,12 @@
h: 24,
svg: `<path d="M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26 5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z"/>`
},
{
name: "network",
w: 24,
h: 24,
svg: `<path d="M17 18a2 2 0 1 1 0 4 2 2 0 0 1 0-4zM7 16a2 2 0 1 1 0 4 2 2 0 0 1 0-4zm10-8a2 2 0 1 1 0 4 2 2 0 0 1 0-4zM7 8a2 2 0 1 1 0 4 2 2 0 0 1 0-4zM19.071 7.071l-10 10-1.414-1.414 10-10 1.414 1.414z"/>`
},
{
name: "logo",
w: 210,

View File

@ -5,15 +5,16 @@
import Icon from "./Icon.svelte";
</script>
<div class="h-full w-72 bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700">
<div class="flex items-center justify-between mx-6 mt-4">
<div class="h-full w-full">
<div class="flex items-center justify-between mx-6 mt-4 pt-14 md:pt-4">
<div class="flex items-center flex-shrink-0">
<Icon name="logo" width="2.5rem" height="2.5rem" />
<span class="text-gray-800 dark:text-gray-100 ml-2 text-3xl font-thin">ESPresense</span>
</div>
<DarkModeToggle />
</div>
<nav class="mt-6 px-6">
<nav class="mt-6 px-6 space-y-1">
<SidebarItem icon="network" title="Network" href="{base}/network" />
<SidebarItem icon="contact" title="Settings" href="{base}/settings" />
<SidebarItem icon="device" title="Devices" href="{base}/devices" />
<SidebarItem icon="fingerprint" title="Fingerprints" href="{base}/fingerprints" />

View File

@ -1,5 +1,5 @@
import { readable, writable } from 'svelte/store';
import type { Extras, Configs, Devices, WebSocketCommand, StartFunction } from './types';
import type { ExtraSettings, Configs, Devices, WebSocketCommand, StartFunction, MainSettings } from './types';
// Room name store that stops polling once room name is found
export const roomName = readable<string>('', function start(set) {
@ -58,19 +58,6 @@ if (typeof window !== 'undefined') {
});
}
// Export the stores with their types
export const extras = writable<Extras | null>({}, function start(set) {
fetch("/extras")
.then(d => d.json())
.then((r: Extras) => {
set(r);
})
.catch((ex) => {
set(null);
console.log(ex);
});
});
export const configs = readable<Configs | null>({ room: '', configs: [] }, function start(set) {
let errors = 0;
let outstanding = false;
@ -155,3 +142,29 @@ export function cancelEnroll(): void {
console.log("Send: " + data);
socket?.send(data);
}
export const mobileMenuOpen = writable<boolean>(false);
export const extraSettings = writable<ExtraSettings | null>({}, function start(set) {
fetch("/wifi/extras")
.then(d => d.json())
.then((r: ExtraSettings) => {
set(r);
})
.catch((ex) => {
set(null);
console.log(ex);
});
});
export const mainSettings = writable<MainSettings | null>(null, function start(set) {
fetch("/wifi/main")
.then(d => d.json())
.then((r: MainSettings) => {
set(r);
})
.catch((ex) => {
set(null);
console.log(ex);
});
});

View File

@ -53,8 +53,13 @@ export interface TableColumn<T> {
class?: string;
}
export interface Extras {
[key: string]: any;
export interface ExtraSettings {
values: {
[key: string]: any;
};
defaults: {
[key: string]: any;
};
}
export interface WebSocketCommand {
@ -63,3 +68,45 @@ export interface WebSocketCommand {
}
export type StartFunction<T> = (set: (value: T) => void) => (() => void) | void;
export interface MainSettings {
values: {
room: string;
wifi_timeout: number;
portal_timeout: number;
"wifi-ssid": string;
"wifi-password": string;
eth: string;
mqtt_host: string;
mqtt_port: number;
mqtt_user: string;
mqtt_pass: string;
discovery: boolean;
discovery_prefix: string;
pub_tele: boolean;
pub_rooms_dep: boolean;
pub_devices: boolean;
auto_update: boolean;
prerelease: boolean;
arduino_ota: boolean;
update: string;
};
defaults: {
room: string;
"wifi-ssid": string;
"wifi-password": string;
wifi_timeout: number;
portal_timeout: number;
eth: string;
mqtt_host: string;
mqtt_port: number;
discovery: boolean;
discovery_prefix: string;
pub_tele: boolean;
pub_rooms_dep: boolean;
pub_devices: boolean;
auto_update: boolean;
prerelease: boolean;
arduino_ota: boolean;
};
}

View File

@ -1,7 +1,9 @@
<script lang="ts">
import Sidebar from "$lib/components/Sidebar.svelte";
import { roomName } from "$lib/stores";
import HamburgerButton from "$lib/components/HamburgerButton.svelte";
import { roomName, mobileMenuOpen } from "$lib/stores";
import { page } from "$app/stores";
import { onMount } from "svelte";
import "../app.css";
// Get the current page name from the URL
@ -12,14 +14,49 @@
$: if (typeof document !== 'undefined') {
document.title = `ESPresense ${$roomName ? `(${$roomName})` : ''} - ${pageTitle}`;
}
// Close mobile menu when clicking outside
function handleClickOutside(event: MouseEvent) {
const target = event.target as HTMLElement;
if ($mobileMenuOpen && !target.closest('nav') && !target.closest('button')) {
mobileMenuOpen.set(false);
}
}
// Close mobile menu on route change
$: if ($page) {
mobileMenuOpen.set(false);
}
// Prevent body scroll when mobile menu is open
$: if (typeof document !== 'undefined') {
if ($mobileMenuOpen) {
document.body.style.overflow = 'hidden';
} else {
document.body.style.overflow = '';
}
}
</script>
<div class="flex h-screen bg-gray-100 dark:bg-gray-900">
<nav class="flex-none w-72 bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700">
<div class="flex h-screen bg-gray-100 dark:bg-gray-900" on:click={handleClickOutside}>
<!-- Mobile menu overlay -->
{#if $mobileMenuOpen}
<div class="fixed inset-0 bg-gray-600 bg-opacity-75 transition-opacity md:hidden" />
{/if}
<!-- Mobile menu button -->
<div class="fixed top-4 left-4 z-40 md:hidden">
<HamburgerButton />
</div>
<!-- Sidebar -->
<nav class="fixed md:static inset-y-0 left-0 transform {$mobileMenuOpen ? 'translate-x-0' : '-translate-x-full'} md:translate-x-0 w-72 bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 transition-transform duration-300 ease-in-out z-30">
<Sidebar />
</nav>
<main class="flex-1 overflow-auto bg-white dark:bg-gray-900">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<!-- Main content -->
<main class="flex-1 overflow-auto bg-white dark:bg-gray-900 md:ml-72">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 mt-14 md:mt-0">
<slot />
</div>
</main>

View File

@ -4,7 +4,7 @@ import { base } from '$app/paths';
import { onMount } from 'svelte';
onMount(() => {
goto(`${base}/settings`);
goto(`${base}/network`);
});
</script>

View File

@ -0,0 +1,323 @@
<script lang="ts">
import { onMount, onDestroy } from "svelte";
import { mainSettings } from "$lib/stores";
import type { MainSettings } from "$lib/types";
let s = $state(false);
let wifiNetworks: Record<string, number> = $state({});
let isScanning = $state(false);
let isDestroyed = false;
async function fetchWifiNetworks() {
if (isScanning || isDestroyed) return; // Prevent concurrent scans and post-destroy scans
try {
isScanning = true;
const response = await fetch("/wifi/scan");
const data = await response.json();
if (data.networks) {
wifiNetworks = data.networks;
} else {
console.error("Unexpected response format:", data);
}
} catch (error) {
console.error("Failed to fetch Wi-Fi networks:", error);
} finally {
isScanning = false;
// Schedule next scan after 5 seconds
if (!isDestroyed) {
setTimeout(fetchWifiNetworks, 5000);
}
}
}
function startScanCycle() {
requestAnimationFrame(fetchWifiNetworks);
}
onMount(() => {
startScanCycle();
});
onDestroy(() => {
isDestroyed = true;
});
async function handleSubmit(event: SubmitEvent) {
try {
event.preventDefault();
s = true;
const form = event.target as HTMLFormElement;
const formData = new FormData(form);
const params = new URLSearchParams();
for (const [key, value] of formData.entries()) {
if (typeof value === "string") {
params.append(key, value);
}
}
await fetch("/wifi/main", { method: "POST", body: params });
try {
await fetch("/restart", { method: "POST", signal: AbortSignal.timeout(1000)});
} catch (error) {
// often the restart request will fail, so we ignore the error
}
// Reload settings after save, with retries
let retries = 5;
let data;
while (retries > 0) {
try {
const response = await fetch("/wifi/main");
data = await response.json();
mainSettings.set(data);
break; // Exit loop on success
} catch (error) {
retries--;
if (retries === 0) {
console.error("Failed to reload settings after multiple retries:", error);
// Optionally display an error message to the user
break;
}
// Wait for 1 second before retrying
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
} finally {
s = false;
}
}
// Make sure your store's data keys match the names below.
const mainSettingsData = $derived($mainSettings as MainSettings);
</script>
<div class="bg-gray-100 dark:bg-gray-800 rounded-lg shadow p-6">
{#if mainSettingsData != null && $mainSettings?.defaults != null && $mainSettings?.values != null}
<form onsubmit={handleSubmit} class="space-y-6">
<!-- Room Configuration -->
<h2 class="text-xl font-semibold">Room Configuration</h2>
<div>
<label class="block text-sm font-medium">Room Name</label>
<input type="text" name="room" bind:value={$mainSettings.values.room} placeholder={$mainSettings.defaults.room} class="mt-1 block w-full rounded-md" />
</div>
<!-- WiFi Configuration -->
<h2 class="text-xl font-semibold">WiFi Configuration</h2>
<div class="mb-2">
<label class="block text-sm font-medium mb-1">WiFi SSID</label>
<input
type="text"
name="wifi-ssid"
bind:value={$mainSettings.values["wifi-ssid"]}
placeholder="Enter WiFi SSID"
class="block w-full rounded-xl border-gray-600 bg-gray-800 dark:text-white px-4 py-3 text-base focus:border-blue-500 focus:ring-blue-500"
/>
</div>
<div>
<div class="bg-gray-50 dark:bg-gray-900 rounded-xl shadow-sm border border-gray-200 dark:border-gray-600">
<div class="px-4 py-3 flex items-center justify-between border-b border-gray-200 dark:border-gray-700">
<label class="text-base font-medium dark:text-white">Available Networks</label>
{#if isScanning}
<div class="ios-spinner"></div>
{/if}
</div>
<ul class="divide-y divide-gray-200 dark:divide-gray-700">
{#each Object.entries(wifiNetworks) as [ssid, rssi]}
<li
onclick={() => {$mainSettings.values["wifi-ssid"] = ssid}}
class="flex items-center cursor-pointer px-4 py-3 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
>
<div class="flex-grow">
<div class="text-base dark:text-white">{ssid}</div>
</div>
<div class="flex items-center space-x-2">
<div class="flex" title={`Signal Strength: ${rssi} dBm`}>
{#each Array(3) as _, i}
<div
class={`w-1.5 h-3 mx-0.5 rounded-sm transform origin-bottom ${
Math.abs(rssi) < (90 - i * 15)
? 'bg-blue-500 dark:bg-blue-400'
: 'bg-gray-300 dark:bg-gray-600'
}`}
style={`transform: scale(1, ${0.6 + i * 0.2})`}
/>
{/each}
</div>
</div>
</li>
{/each}
</ul>
</div>
</div>
<div>
<label class="block text-sm font-medium">WiFi Password</label>
<input type="password" name="wifi-password" bind:value={$mainSettings.values["wifi-password"]} placeholder="Enter WiFi Password" class="mt-1 block w-full rounded-md" />
</div>
<div>
<label class="block text-sm font-medium"> Seconds to wait for WiFi before captive portal (-1 = forever) </label>
<input type="number" name="wifi_timeout" bind:value={$mainSettings.values.wifi_timeout} placeholder={String($mainSettings.defaults.wifi_timeout)} step="1" min="-2147483648" max="2147483647" class="mt-1 block w-full rounded-md" />
</div>
<div>
<label class="block text-sm font-medium"> Seconds to wait in captive portal before rebooting </label>
<input type="number" name="portal_timeout" bind:value={$mainSettings.values.portal_timeout} placeholder={String($mainSettings.defaults.portal_timeout)} step="1" min="-2147483648" max="2147483647" class="mt-1 block w-full rounded-md" />
</div>
<div>
<label class="block text-sm font-medium">Ethernet Type</label>
<select name="eth" bind:value={$mainSettings.values.eth} class="mt-1 block w-full rounded-md">
<option value="0">None</option>
<option value="1">WT32-ETH01</option>
<option value="2">ESP32-POE</option>
<option value="3">WESP32</option>
<option value="4">QuinLED-ESP32</option>
<option value="5">TwilightLord-ESP32</option>
<option value="6">ESP32Deux</option>
<option value="7">KIT-VE</option>
<option value="8">LilyGO-T-ETH-POE</option>
<option value="9">GL-inet GL-S10 v2.1 Ethernet</option>
<option value="10">EST-PoE-32</option>
</select>
</div>
<!-- MQTT Configuration -->
<h2 class="text-xl font-semibold">MQTT Configuration</h2>
<div>
<label class="block text-sm font-medium">Server</label>
<input type="text" name="mqtt_host" bind:value={$mainSettings.values.mqtt_host} placeholder={$mainSettings.defaults.mqtt_host} class="mt-1 block w-full rounded-md" />
</div>
<div>
<label class="block text-sm font-medium">Port</label>
<input type="number" name="mqtt_port" bind:value={$mainSettings.values.mqtt_port} placeholder={String($mainSettings.defaults.mqtt_port)} step="1" min="-2147483648" max="2147483647" class="mt-1 block w-full rounded-md" />
</div>
<div>
<label class="block text-sm font-medium">Username</label>
<!-- Using a password input as in the legacy page -->
<input type="password" name="mqtt_user" bind:value={$mainSettings.values.mqtt_user} class="mt-1 block w-full rounded-md" />
</div>
<div>
<label class="block text-sm font-medium">Password</label>
<input type="password" name="mqtt_pass" bind:value={$mainSettings.values.mqtt_pass} class="mt-1 block w-full rounded-md" />
</div>
<div class="space-y-4">
<label class="flex items-center space-x-2">
<input type="checkbox" name="discovery" value="1" bind:checked={$mainSettings.values.discovery} class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
<span>Send to discovery topic</span>
</label>
<div class="ml-6">
<label class="block text-sm font-medium"> Home Assistant discovery topic prefix </label>
<input type="text" name="discovery_prefix" bind:value={$mainSettings.values.discovery_prefix} placeholder={$mainSettings.defaults.discovery_prefix} class="mt-1 block w-full rounded-md" />
</div>
<label class="flex items-center space-x-2">
<input type="checkbox" name="pub_tele" value="1" bind:checked={$mainSettings.values.pub_tele} class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
<span>Send to telemetry topic</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" name="pub_devices" value="1" bind:checked={$mainSettings.values.pub_devices} class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
<span>Send to devices topic</span>
</label>
</div>
<!-- Updating -->
<h2 class="text-xl font-semibold">Updating</h2>
<div class="space-y-4">
<label class="flex items-center space-x-2">
<input type="checkbox" name="auto_update" value="1" bind:checked={$mainSettings.values.auto_update} class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
<span>Automatically update</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" name="prerelease" value="1" bind:checked={$mainSettings.values.prerelease} class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
<span>Include pre-released versions in auto-update</span>
</label>
<label class="flex items-center space-x-2">
<input type="checkbox" name="arduino_ota" value="1" bind:checked={$mainSettings.values.arduino_ota} class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500" />
<span>Arduino OTA Update</span>
</label>
<div>
<label class="block text-sm font-medium"> Update URL (if set will update from this url on next boot) </label>
<input type="text" name="update" bind:value={$mainSettings.values.update} class="mt-1 block w-full rounded-md" />
</div>
</div>
<div class="flex justify-end">
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:ring-4 focus:outline-none focus:ring-blue-300 rounded-lg dark:bg-blue-500 dark:hover:bg-blue-600 dark:focus:ring-blue-800">
{s ? "Saving..." : "Save"}
</button>
</div>
</form>
{/if}
</div>
<style>
:global(input:not([type="checkbox"])) {
@apply border-2 border-gray-300 bg-white focus:border-blue-500 focus:ring-blue-500;
}
:global(.dark input:not([type="checkbox"])) {
@apply border-gray-500 bg-gray-900 text-white;
}
:global(select) {
@apply border-2 border-gray-300 bg-white text-gray-900 focus:border-blue-500 focus:ring-blue-500;
}
:global(.dark select) {
@apply border-gray-500 bg-gray-900 text-white;
}
:global(input[type="checkbox"]) {
@apply h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500;
}
:global(.dark input[type="checkbox"]) {
@apply border-gray-600;
}
:global(h2) {
@apply text-gray-900 mb-4;
}
:global(.dark h2) {
@apply text-white;
}
:global(label) {
@apply text-gray-700 mb-1;
}
:global(.dark label) {
@apply text-white;
}
.ios-spinner {
width: 16px;
height: 16px;
border: 2px solid transparent;
border-top-color: #3b82f6;
border-right-color: #3b82f6;
border-bottom-color: #3b82f6;
border-radius: 50%;
animation: spin 1s cubic-bezier(0.42, 0.61, 0.58, 0.41) infinite;
opacity: 0.8;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
:global(.dark .ios-spinner) {
border-top-color: #60a5fa;
border-right-color: #60a5fa;
border-bottom-color: #60a5fa;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -9,12 +9,12 @@ const config = {
adapter: adapter(),
prerender: {
crawl: false,
entries: ['/', '/settings', '/devices', '/fingerprints'],
entries: ['/', '/settings', '/devices', '/fingerprints', '/network'],
handleHttpError: 'warn',
},
appDir: 'app',
paths: {
base: '/ui'
base: ''
},
version: {
name: '',

View File

@ -10,7 +10,7 @@ export default defineConfig({
include: '**/*.(js|ts|svelte)',
functions: ['console.*', 'assert.*'],
}),
cppPlugin({ basePath: '/ui', outPrefix: 'ui_' })
cppPlugin({ basePath: '', outPrefix: 'ui_' })
],
build: {
sourcemap: false,
@ -22,10 +22,11 @@ export default defineConfig({
},
server: {
proxy: {
'/json': 'http://192.168.128.165',
'/extras': 'http://192.168.128.165',
'/json': 'http://192.168.129.176',
'/wifi': 'http://192.168.129.176',
'/restart': 'http://192.168.129.176',
'/ws': {
target: 'ws://192.168.128.165',
target: 'ws://192.168.129.176',
ws: true,
}
}

File diff suppressed because one or more lines are too long