diff --git a/.vs/BLLEDController/v16/.suo b/.vs/BLLEDController/v16/.suo
new file mode 100644
index 0000000..121a984
Binary files /dev/null and b/.vs/BLLEDController/v16/.suo differ
diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite
new file mode 100644
index 0000000..25b3cee
Binary files /dev/null and b/.vs/slnx.sqlite differ
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 909b171..567aba2 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -29,7 +29,10 @@
"filesystem": "cpp",
"fstream": "cpp",
"locale": "cpp",
- "random": "cpp"
+ "random": "cpp",
+ "sstream": "cpp",
+ "cmath": "cpp",
+ "algorithm": "cpp"
},
"cmake.configureOnOpen": false
}
\ No newline at end of file
diff --git a/esphome.html b/esphome.html
new file mode 100644
index 0000000..9445843
--- /dev/null
+++ b/esphome.html
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/firmware/manifestexpirimental.json b/firmware/manifestexpirimental.json
index d5035da..ef1b302 100644
--- a/firmware/manifestexpirimental.json
+++ b/firmware/manifestexpirimental.json
@@ -1,12 +1,12 @@
{
"name": "BLLEDCONTROLLER",
- "version": "Experimental 25 2 24",
+ "version": "Experimental 16 3 24",
"new_install_prompt_erase": true,
"builds": [
{
"chipFamily": "ESP32",
"parts": [
- { "path": "esp32dev/BLLC_Experimental_25.2.24.bin", "offset": 0 }
+ { "path": "esp32dev/BLLC_Experimental_16.3.24.bin", "offset": 0 }
]
}
]
diff --git a/src/AutoGrowBufferStream.h b/src/AutoGrowBufferStream.h
index 66547f9..95c2fd0 100644
--- a/src/AutoGrowBufferStream.h
+++ b/src/AutoGrowBufferStream.h
@@ -29,7 +29,7 @@ class AutoGrowBufferStream : public Stream
if (this->_len + 1 > this->buffer_size) {
auto tmp = (char*)realloc(this->_buffer, this->buffer_size + BUFFER_INCREMENTS);
if (tmp == NULL) {
- Serial.println("Failed to grow buffer");
+ Serial.println(F("Failed to grow buffer"));
return 0;
}
this->_buffer = tmp;
diff --git a/src/filesystem.h b/src/filesystem.h
index 6b23d65..a10d912 100644
--- a/src/filesystem.h
+++ b/src/filesystem.h
@@ -26,29 +26,50 @@ char* generateRandomString(int length) {
void saveFileSystem(){
Serial.println(F("Saving config"));
-
- DynamicJsonDocument json(512);
- json["brightness"] = printerConfig.brightness;
+
+ JsonDocument json;
json["printerIp"] = printerConfig.printerIP;
json["accessCode"] = printerConfig.accessCode;
json["serialNumber"] = printerConfig.serialNumber;
+ json["ssid"] = globalVariables.SSID;
+ json["appw"] = globalVariables.APPW;
//json["webpagePassword"] = printerConfig.webpagePassword;
-
+ json["bssi"] = printerConfig.BSSID;
+ json["brightness"] = printerConfig.brightness;
+ // BLLED Settings
json["replicatestate"] = printerConfig.replicatestate;
json["errordetection"] = printerConfig.errordetection;
json["finishindication"] = printerConfig.finishindication;
+ json["lidarLightsOff"] = printerConfig.lidarLightsOff;
+ json["inactivityEnabled"] = printerConfig.inactivityEnabled;
+ json["inactivityTimeOut"] = printerConfig.inactivityTimeOut;
+ json["discoMode"] = printerConfig.discoMode;
+ json["maintMode"] = printerConfig.maintMode;
+ // Debugging
+ json["debuging"] = printerConfig.debuging;
+ json["debugingchange"] = printerConfig.debugingchange;
json["mqttdebug"] = printerConfig.mqttdebug;
-
- json["ssid"] = globalVariables.SSID;
- json["appw"] = globalVariables.APPW;
-
+ // Test - Fixed LED Colors
+ json["testRGB"] = printerConfig.testRGB;
+ json["testwarmwhite"] = printerConfig.testwarmwhite;
+ json["testcoldwhite"] = printerConfig.testcoldwhite;
+ // Customise LED Colors
+ json["wifiRGB"] = printerConfig.wifiRGB;
+ json["finishRGB"] = printerConfig.finishRGB;
+ json["pauseRGB"] = printerConfig.pauseRGB;
+ json["firstlayerRGB"] = printerConfig.firstlayerRGB;
+ json["nozzleclogRGB"] = printerConfig.nozzleclogRGB;
+ json["hmsSeriousRGB"] = printerConfig.hmsSeriousRGB;
+ json["hmsFatalRGB"] = printerConfig.hmsFatalRGB;
+ json["filamentRunoutRGB"] = printerConfig.filamentRunoutRGB;
+ json["frontCoverRGB"] = printerConfig.frontCoverRGB;
+ json["nozzleTempRGB"] = printerConfig.nozzleTempRGB;
+ json["bedTempRGB"] = printerConfig.bedTempRGB;
File configFile = LittleFS.open(configPath, "w");
-
if (!configFile) {
Serial.println(F("Failed to save config"));
return;
}
-
serializeJson(json, configFile);
configFile.close();
Serial.println(F("Config Saved"));
@@ -66,41 +87,63 @@ void loadFileSystem(){
}
attempts++;
Serial.println(F("Failed to open config file, retrying.."));
- delay(3000);
+ delay(2000);
}
-
if (!configFile) {
- Serial.println(F("Failed to open config file after retries"));
+ Serial.print(F("Failed to open config file after "));
+ Serial.print(attempts);
+ Serial.println(F(" retries"));
+
Serial.println(F("Clearing config"));
// LittleFS.remove(configPath);
saveFileSystem();
return;
}
-
size_t size = configFile.size();
-
std::unique_ptr buf(new char[size]);
configFile.readBytes(buf.get(), size);
- DynamicJsonDocument json(512);
-
+ JsonDocument json;
auto deserializeError = deserializeJson(json, buf.get());
if (!deserializeError) {
- printerConfig.brightness = json["brightness"];
-
+ strcpy(globalVariables.SSID, json["ssid"]);
+ strcpy(globalVariables.APPW, json["appw"]);
strcpy(printerConfig.printerIP, json["printerIp"]);
strcpy(printerConfig.accessCode, json["accessCode"]);
strcpy(printerConfig.serialNumber, json["serialNumber"]);
//strcpy(printerConfig.webpagePassword, json["webpagePassword"]);
-
- strcpy(globalVariables.SSID, json["ssid"]);
- strcpy(globalVariables.APPW, json["appw"]);
-
+ strcpy(printerConfig.BSSID, json["bssi"]);
+ printerConfig.brightness = json["brightness"];
+ //BLLED Settings
printerConfig.replicatestate = json["replicatestate"];
printerConfig.errordetection = json["errordetection"];
printerConfig.finishindication = json["finishindication"];
+ printerConfig.lidarLightsOff = json["lidarLightsOff"];
+ printerConfig.inactivityEnabled = json["inactivityEnabled"];
+ printerConfig.inactivityTimeOut = json["inactivityTimeOut"];
+ printerConfig.discoMode = json["discoMode"];
+ printerConfig.maintMode = json["maintMode"];
+ //Debugging
+ printerConfig.debuging = json["debuging"];
+ printerConfig.debugingchange = json["debugingchange"];
printerConfig.mqttdebug = json["mqttdebug"];
+ //Test - Fixed LED Colors
+ strcpy(printerConfig.testRGB, json["testRGB"]);
+ printerConfig.testwarmwhite = json["testwarmwhite"];
+ printerConfig.testcoldwhite = json["testcoldwhite"];
+ // Customise LED Colors
+ strcpy(printerConfig.wifiRGB, json["wifiRGB"]);
+ strcpy(printerConfig.finishRGB, json["finishRGB"]);
+ strcpy(printerConfig.pauseRGB, json["pauseRGB"]);
+ strcpy(printerConfig.firstlayerRGB, json["firstlayerRGB"]);
+ strcpy(printerConfig.nozzleclogRGB, json["nozzleclogRGB"]);
+ strcpy(printerConfig.hmsSeriousRGB, json["hmsSeriousRGB"]);
+ strcpy(printerConfig.hmsFatalRGB, json["hmsFatalRGB"]);
+ strcpy(printerConfig.filamentRunoutRGB, json["filamentRunoutRGB"]);
+ strcpy(printerConfig.frontCoverRGB, json["frontCoverRGB"]);
+ strcpy(printerConfig.nozzleTempRGB, json["nozzleTempRGB"]);
+ strcpy(printerConfig.bedTempRGB, json["bedTempRGB"]);
Serial.println(F("Loaded config"));
} else {
@@ -131,6 +174,8 @@ void setupFileSystem(){
Serial.println(F("Failed to mount LittleFS"));
LittleFS.format();
Serial.println(F("Formatting LittleFS"));
+ Serial.println(F("Restarting Device"));
+ delay(1000);
ESP.restart();
}
Serial.println(F("Mounted LittleFS"));
diff --git a/src/leds.h b/src/leds.h
index c935d45..00c5e47 100644
--- a/src/leds.h
+++ b/src/leds.h
@@ -16,7 +16,30 @@ int currentBlue = 0;
int currentWarm = 0;
int currentCold = 0;
-void tweenToColor(int targetRed, int targetGreen, int targetBlue, int targetWarm, int targetCold, int duration) {
+struct COLOR {
+ short r;
+ short g;
+ short b;
+};
+
+COLOR hex2rgb(String hex) {
+ COLOR color;
+ long hexcolor;
+
+ if(hex.charAt(0) == '#') {
+ hex.remove(0,1);
+ }
+ while(hex.length() != 6) {
+ hex += "0";
+ }
+ hexcolor = strtol(hex.c_str(), NULL, 16);
+ color.r = (hexcolor & 0xFF0000) >> 16;
+ color.g = (hexcolor & 0x00FF00) >> 8;
+ color.b = (hexcolor & 0x0000FF);
+ return color;
+}
+
+void tweenToColor(int targetRed, int targetGreen, int targetBlue, int targetWarm, int targetCold, int duration = 500) {
float brightness = (float)printerConfig.brightness/100.0;
@@ -27,10 +50,23 @@ void tweenToColor(int targetRed, int targetGreen, int targetBlue, int targetWarm
int brightenedCold = round(targetCold * brightness);
if (brightenedRed == currentRed && brightenedGreen == currentGreen && brightenedBlue == currentBlue && brightenedWarm == currentWarm && brightenedCold == currentCold){
+ // Already set to the requested color
if (printerConfig.debuging){
- Serial.println(F("LEDS Trying to change to the same color."));
+ Serial.print(F("LEDS already at color: ("));
+ Serial.print(currentRed);
+ Serial.print(F(", "));
+ Serial.print(currentGreen);
+ Serial.print(F(", "));
+ Serial.print(currentBlue);
+ Serial.print(F(", "));
+ Serial.print(currentWarm);
+ Serial.print(F(", "));
+ Serial.print(currentCold);
+ Serial.print(F(" Brightness: "));
+ Serial.print(printerConfig.brightness);
+ Serial.println(F(")"));
};
- return; // already at that color
+ return;
}
float stepTime = (float)duration / 255.0;
int redStep = (brightenedRed - currentRed) / 255;
@@ -65,19 +101,29 @@ void tweenToColor(int targetRed, int targetGreen, int targetBlue, int targetWarm
analogWrite(bluePin, currentBlue);
analogWrite(warmPin, currentWarm);
analogWrite(coldPin, currentCold);
-
- //Serial.println(F("Leds: "));
- //Serial.println(currentRed);
- //Serial.println(currentGreen);
- //Serial.println(currentBlue);
- //Serial.println(currentWarm);
- //Serial.println(currentCold);
+}
+
+//Helper functions to allow changes colors by using a string or integer hex code
+//Example: tweenToColor("#33FD67")
+void tweenToColor(String strTargetColor) {
+ COLOR targetcolor;
+ targetcolor = hex2rgb(strTargetColor);
+ tweenToColor(targetcolor.r, targetcolor.g, targetcolor.b, 0, 0);
+}
+//Example: tweenToColor(0xFFACA5)
+void tweenToColor(int hexValue) {
+ COLOR targetcolor;
+ targetcolor.r = ((hexValue >> 16) & 0xFF) / 255.0;
+ targetcolor.g = ((hexValue >> 8) & 0xFF) / 255.0;
+ targetcolor.b = ((hexValue) & 0xFF) / 255.0;
+ tweenToColor(targetcolor.r, targetcolor.g, targetcolor.b, 0, 0);
}
float hue = 0.0;
void RGBCycle() {
- if (printerConfig.turbo == false) {
+ if (printerConfig.discoMode == false) {
+ //Skip changing colors if RGB Mode not enabled
return;
}
if (printerVariables.online == false) {
@@ -99,6 +145,15 @@ void RGBCycle() {
currentWarm = 0;
currentCold = 0;
+ //Adjust to set brightness level
+ float brightness = (float)printerConfig.brightness/100.0;
+
+ int brightenedRed = round(currentRed * brightness);
+ int brightenedGreen = round(currentGreen * brightness);
+ int brightenedBlue = round(currentBlue * brightness);
+ int brightenedWarm = round(currentWarm * brightness);
+ int brightenedCold = round(currentCold * brightness);
+
analogWrite(redPin, currentRed);
analogWrite(greenPin, currentGreen);
analogWrite(bluePin, currentBlue);
@@ -106,172 +161,419 @@ void RGBCycle() {
analogWrite(coldPin, currentCold);
}
+
+
+void idleStatus(){
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage "));
+ Serial.print(printerVariables.stage);
+ Serial.print(F(", IDLE Turning LEDs to WHITE. Brightness: "));
+ Serial.println(printerConfig.brightness);
+ };
+}
+
+
+
void updateleds(){
- if (printerConfig.debuging){
- Serial.println(F("Updating leds"));
+ //Maintenance Mode - White lights on regardless of printer power, WiFi or MQTT connection
+ //priortised over Wifi Strength Display or Custom TEST color
+ if (printerConfig.maintMode && printerConfig.updateMaintenance){
+ tweenToColor(0,0,0,255,255); //WHITE
+ printerConfig.updateMaintenance = false;
+ if (printerConfig.debugingchange){
+ Serial.println(F("Maintenance Mode, turning LEDs to WHITE"));
+ };
+ return;
+ }
+
+ //Use LED to show WIFI Strength (enabled via Setup Webpage, priortised over Custom TEST color)
+ if (printerConfig.debugwifi == true && !printerConfig.maintMode){
+ //<=-50 dBm Green, <= -60 dBm LightGreen, <= -70 dBm Yellow, <= -80 dBm Orange, >80 Red
+ if (WiFi.status() == WL_CONNECTED){
+ long wifiNow = WiFi.RSSI();
+ if (printerConfig.debugingchange){
+ Serial.print(F("WiFi Strength Visialisation, display LEDs for: "));
+ Serial.println(wifiNow);
+ }
+ if (wifiNow >= -50) tweenToColor(0,255,0,0,0); //GREEN
+ else if (wifiNow >= -60) tweenToColor(128,255,0,0,0); //LIGHTGREEN
+ else if (wifiNow >= -70) tweenToColor(255,255,0,0,0); //YELLOW
+ else if (wifiNow >= -80) tweenToColor(255,128,0,0,0); //ORANGE
+ else if (wifiNow < -80) tweenToColor(255,0,0,0,0); //RED
+ else tweenToColor(0,0,255,0,0); //BLUE
+ };
+ return;
+ }
+
+ //TEST Color Enabled - LED ON regardless of printer state
+ if (printerVariables.testcolorEnabled && !printerConfig.maintMode && !printerConfig.debugwifi){
+ COLOR customColor = hex2rgb(printerConfig.testRGB);
+
+ tweenToColor(customColor.r,customColor.g,customColor.b,printerConfig.testwarmwhite,printerConfig.testcoldwhite); //Variable Test Color
+ if (printerConfig.debugingchange){
+ Serial.print(F("LED Test ON, Changing LEDs to selected color: "));
+ Serial.print(customColor.r);
+ Serial.print(F(" "));
+ Serial.print(customColor.g);
+ Serial.print(F(" "));
+ Serial.print(customColor.b);
+ Serial.print(F(" "));
+ Serial.print(printerConfig.testwarmwhite);
+ Serial.print(F(" "));
+ Serial.print(printerConfig.testcoldwhite);
+ Serial.print(F(" Brightness: "));
+ Serial.println(printerConfig.brightness);
+ };
+ printerConfig.updateTestLEDS = false;
+ return;
+ }
+
+ if(printerVariables.testcolorEnabled || printerConfig.maintMode || printerConfig.debugwifi){
+ //Skip trying to set a color as it's in one of the override states
+ return;
+ }
+
+ //From here the BBLP status sets the colors
+ if (printerConfig.debuging == true){
+ Serial.println(F("Updating LEDs"));
Serial.println(printerVariables.stage);
Serial.println(printerVariables.gcodeState);
- Serial.println(printerVariables.ledstate);
+ Serial.println(printerVariables.printerledstate);
Serial.println(printerVariables.hmsstate);
Serial.println(printerVariables.parsedHMS);
}
- //OFF
- if (printerConfig.turbo == true){
+ //TOGGLE LIGHTS via DOOR
+ //If door is closed twice in 6 seconds, it will flip the state of the lights
+ if (printerVariables.doorSwitchenabled == true){
+ if (printerConfig.debugingchange){
+ Serial.print(F("Door closed twice within 6 seconds - Toggling LEDs to "));
+ }
+ if(currentWarm == 0 && currentCold == 0)
+ {
+ tweenToColor(0,0,0,255,255); //WHITE
+ if (printerConfig.debuging || printerConfig.debugingchange) {
+ Serial.println(F("ON"));
+ }
+ }
+ else
+ {
+ tweenToColor(0,0,0,0,0); //OFF
+ //Shortcut to idle state - note: light will go back on immediately if there is an MQTT change of any sort
+ printerVariables.inactivityLightsOff = true;
+ printerVariables.inactivityStartms = millis()-printerConfig.inactivityTimeOut;
+ if (printerConfig.debuging || printerConfig.debugingchange) {
+ Serial.println(F("OFF"));
+ }
+ }
+ printerVariables.doorSwitchenabled = false;
+ }
+
+
+ //OFF -- OFF -- OFF -- OFF
+
+ if (printerConfig.discoMode == true){
+ //Skip all the following code that sets specific colors if RGB Mode is on - done in RGBCycle()
return;
}
- if (printerVariables.online == false){ //printer offline
- tweenToColor(0,0,0,0,0,500); //OFF
- if (printerConfig.debuging){
- Serial.println(F("Printer offline, Turning Leds off"));
+ //printer offline and MQTT disconnect more than 5 seconds.
+ if (printerVariables.online == false && (millis() - printerVariables.disconnectMQTTms) >= 5000){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Printer offline, Turning LEDs OFF"));
};
return;
}
- if (printerVariables.ledstate == false && printerConfig.replicatestate == true){ // replicate printer behaviour
- tweenToColor(0,0,0,0,0,500); //OFF
- if (printerConfig.debuging){
- Serial.println(F("Chamber light off, Turning Leds off"));
+ // replicate printer behaviour
+ if (printerVariables.printerledstate == false && printerConfig.replicatestate == true){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("LED Replication, Turning LEDs OFF"));
};
return;
}
- if (printerVariables.stage == 14){ //Cleaning nozzle
- tweenToColor(0,0,0,0,0,500); //OFF
- if (printerConfig.debuging){
- Serial.println(F("Cleaning nozzle, Turning Leds off"));
+ //Cleaning nozzle
+ if (printerVariables.stage == 14 && printerConfig.lidarLightsOff){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 14, CLEANING NOZZLE, Turning LEDs OFF"));
};
return;
}
- if (printerVariables.stage == 9){ //Scaning surface
- tweenToColor(0,0,0,0,0,500); //OFF
- if (printerConfig.debuging){
- Serial.println(F("Scanning Surface, Turning Leds off"));
+ //Auto Bed Leveling
+ if (printerVariables.stage == 1 && printerConfig.lidarLightsOff){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 1, BED LEVELING, Turning LEDs OFF"));
+ };
+ return;
+ }
+
+ //Calibrating Extrusion
+ if (printerVariables.stage == 8 && printerConfig.lidarLightsOff){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 8, CALIBRATING EXTRUSION, Turning LEDs OFF"));
+ };
+ return;
+ }
+
+ //Scaning surface
+ if (printerVariables.stage == 9 && printerConfig.lidarLightsOff){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 9, SCANNING BED SURFACE, Turning LEDs OFF"));
+ };
+ return;
+ }
+
+ //Inspecting First Layer
+ if ((printerVariables.stage == 10 && printerConfig.lidarLightsOff)
+ || (printerVariables.inspectingFirstLayer && printerConfig.lidarLightsOff)){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 10 / HMS 0C00, FIRST LAYER INSPECTION, Turning LEDs OFF"));
+ };
+ return;
+ }
+
+ //Calibrating MicroLidar
+ if (printerVariables.stage == 12 && printerConfig.lidarLightsOff){
+ tweenToColor(0,0,0,0,0); //OFF
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 12, CALIBRATING MICRO LIDAR, Turning LEDs OFF"));
+ };
+ return;
+ }
+
+ // Idle Timeout (Has to be enabled)
+ if ((printerVariables.stage == -1 || printerVariables.stage == 255)
+ && !printerVariables.waitingForDoor
+ && (millis() - printerVariables.inactivityStartms) > printerConfig.inactivityTimeOut
+ && printerVariables.inactivityLightsOff == false
+ && printerConfig.inactivityEnabled){
+ tweenToColor(0,0,0,0,0); //OFF
+ printerVariables.inactivityLightsOff = true;
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Idle Timeout ["));
+ Serial.print((int)(printerConfig.inactivityTimeOut / 60000));
+ Serial.println(F(" mins] - Turning LEDs OFF"));
};
return;
}
- //RED
+ //RED -- RED -- RED -- RED
- if (printerConfig.errordetection == true){ // allow errordetection to turn ledstrip red
+ // allow errordetection to turn ledstrip red
+ if (printerConfig.errordetection == true){
+
+ //SERIOUS HMS state
if (printerVariables.parsedHMS == "Serious"){
- tweenToColor(255,0,0,0,0,500); //RED
- if (printerConfig.debuging){
- Serial.println(F("Serious problem, Turning Leds red"));
+ tweenToColor(printerConfig.hmsSeriousRGB); //Customisable - Default is RED
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("HMS Severity, SERIOUS PROBLEM, Turning LEDs to "));
+ Serial.println(printerConfig.hmsSeriousRGB);
};
return;
- }
+ };
+ //FATAL HMS state
if (printerVariables.parsedHMS == "Fatal"){
- tweenToColor(255,0,0,0,0,500); //RED
- if (printerConfig.debuging){
- Serial.println(F("Fatal problem, Turning Leds red"));
+ tweenToColor(printerConfig.hmsFatalRGB); //Customisable - Default is RED
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("HMS Severity, FATAL PROBLEM, Turning LEDs to "));
+ Serial.println(printerConfig.hmsFatalRGB);
};
return;
- }
+ };
- if (printerVariables.stage == 6){ //Fillament runout
- tweenToColor(255,0,0,0,0,500); //RED
- if (printerConfig.debuging){
- Serial.println(F("Fillament runout, Turning Leds red"));
+ //Fillament runout
+ if (printerVariables.stage == 6){
+ tweenToColor(printerConfig.filamentRunoutRGB); //Customisable - Default is RED
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 17, FILAMENT RUNOUT, Turning LEDs to "));
+ Serial.println(printerConfig.filamentRunoutRGB);
};
return;
- }
+ };
- if (printerVariables.stage == 17){ //Front Cover Removed
- tweenToColor(255,0,0,0,0,500); //RED
- if (printerConfig.debuging){
- Serial.println(F("Front Cover Removed, Turning Leds red"));
+ //Front Cover Removed
+ if (printerVariables.stage == 17){
+ tweenToColor(printerConfig.frontCoverRGB); //Customisable - Default is RED
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 17, FRONT COVER REMOVED, Turning LEDs to "));
+ Serial.println(printerConfig.frontCoverRGB);
};
return;
- }
+ };
- if (printerVariables.stage == 20){ //Nozzle Temp fail
- tweenToColor(255,0,0,0,0,500); //RED
- if (printerConfig.debuging){
- Serial.println(F("Nozzle Temp fail, Turning Leds red"));
+ //Nozzle Temp fail
+ if (printerVariables.stage == 20){
+ tweenToColor(printerConfig.nozzleTempRGB); //Customisable - Default is RED
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 20, NOZZLE TEMP FAIL, Turning LEDs to "));
+ Serial.println(printerConfig.nozzleTempRGB);
};
return;
- }
+ };
- if (printerVariables.stage == 21){ //Bed Temp Fail
- tweenToColor(255,0,0,0,0,500); //RED
- if (printerConfig.debuging){
- Serial.println(F("Bed Temp fail, Turning Leds red"));
+ //Bed Temp Fail
+ if (printerVariables.stage == 21){
+ tweenToColor(printerConfig.bedTempRGB); //Customisable - Default is RED
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 21, BED TEMP FAIL, Turning LEDs to "));
+ Serial.println(printerConfig.bedTempRGB);
};
return;
- }
+ };
};
- //GREEN
-
- if ((millis() - printerVariables.finishstartms) <= 300000 && printerVariables.gcodeState == "FINISH" && printerConfig.finishindication == true){
- tweenToColor(0,255,0,0,0,500); //ON
- if (printerConfig.debuging){
- Serial.println(F("Finished print, Turning Leds green"));
- Serial.println(F("Leds should stay on for: "));
- Serial.print((millis() - printerVariables.finishstartms));
- Serial.print(F(" MS"));
+ //BLUE -- BLUE -- BLUE -- BLUE
+
+ // Pause (by user or via Gcode)
+ if ((printerVariables.stage == 6 || printerVariables.stage == 30) || printerVariables.gcodeState == "PAUSE"){
+ tweenToColor(printerConfig.pauseRGB); //Customisable - Default is BLUE
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage "));
+ Serial.print(printerVariables.stage);
+ Serial.print(F(", gcodeState PAUSE, Turning LEDs to "));
+ Serial.println(printerConfig.pauseRGB);
};
return;
}
- //BLUE
+ //First Layer Error PAUSED
+ if (printerVariables.stage == 34){
+ tweenToColor(printerConfig.firstlayerRGB); //Customisable - Default is BLUE
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 34, FIRST LAYER ERROR, PAUSED Turning LEDs to "));
+ Serial.println(printerConfig.firstlayerRGB);
+ };
+ return;
+ }
- if (printerVariables.stage == 2 && printerVariables.gcodeState == "PAUSE"){// Pause
- tweenToColor(0,0,255,0,0,500); //Blue
- if (printerConfig.debuging){
- Serial.println(F("Pause, Turning Leds blue"));
+ //Nozzle Clog PAUSED
+ if (printerVariables.stage == 35){
+ tweenToColor(printerConfig.nozzleclogRGB); //Customisable - Default is BLUE
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 35, NOZZLE CLOG, PAUSED Turning LEDs to "));
+ Serial.println(printerConfig.nozzleclogRGB);
};
return;
}
- //ON
+ //ON -- ON -- ON -- ON
- if (printerVariables.stage == 0 || printerVariables.stage == 2 && printerVariables.gcodeState == "RUNNING"){ //Printing or Resume after Pausing
- tweenToColor(0,0,0,255,255,500); //ON
- if (printerConfig.debuging){
- Serial.println(F("Printing, Turning Leds On"));
+ //Initial Boot
+ if (printerVariables.initalisedLEDs == false) {
+ tweenToColor(0,0,0,255,255); //WHITE
+ printerVariables.initalisedLEDs = true;
+ printerVariables.inactivityStartms = millis();
+ printerVariables.waitingForDoor = false;
+ printerVariables.lastdoorClosems = millis();
+ Serial.println(F("Initial BLLED bootup - Turning LEDs to WHITE, Start IDLE timer"));
+ return;
+ }
+
+ //Preheating Bed
+ if (printerVariables.stage == 2){
+ tweenToColor(0,0,0,255,255); //WHITE
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Stage 2, PREHEATING BED, Turning LEDs to WHITE"));
};
return;
}
- if (printerVariables.stage == -1){ // Idle
- tweenToColor(0,0,0,255,255,500); //ON
- if (printerConfig.debuging){
- Serial.println(F("Idle, Turning Leds On"));
+ //Printing or Resume after Pausing
+ if (printerVariables.stage == 0 && printerVariables.gcodeState == "RUNNING"){
+ tweenToColor(0,0,0,255,255); //WHITE
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Stage 0, PRINTING - gcodeState RUNNING, Turning LEDs to WHITE. Brightness: "));
+ Serial.println(printerConfig.brightness);
};
return;
}
- if (printerVariables.stage == -2){ //Offline
- tweenToColor(0,0,0,255,255,500); //ON
- if (printerConfig.debuging){
- Serial.println(F("Stage -2, Turning Leds On"));
+ //for IDLE - P1 uses 255, X1 uses -1
+ //This covers both IDLE & FINISH
+ if ((printerVariables.stage == -1 || printerVariables.stage == 255)
+ && printerVariables.waitingForDoor == false
+ && (millis() - printerVariables.inactivityStartms < printerConfig.inactivityTimeOut)){
+ tweenToColor(0,0,0,255,255); //WHITE
+ idleStatus();
+ return;
+ }
+
+ //User Cancelled Print
+ if (printerVariables.gcodeState == "FAILED"){
+ tweenToColor(0,0,0,255,255); //WHITE
+ idleStatus();
+ return;
+ }
+ //Print file just sent
+ if (printerVariables.gcodeState == "PREPARE"){
+ tweenToColor(0,0,0,255,255); //WHITE
+ idleStatus();
+ return;
+ }
+
+ //Offline
+ if (printerVariables.gcodeState == "OFFLINE" || printerVariables.stage == -2){
+ tweenToColor(0,0,0,255,255); //WHITE
+ idleStatus();
+ return;
+ }
+
+ //GREEN -- GREEN -- GREEN -- GREEN
+
+ //Sets to green when print finishes AND user wants Finish Indication enabled
+ if (printerVariables.finished == true && printerConfig.finishindication == true){
+ tweenToColor(printerConfig.finishRGB); //Customisable - Default is GREEN
+ printerVariables.finished = false;
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Finished print, Turning LEDs to "));
+ Serial.println(printerConfig.finishRGB);
};
return;
}
}
+
void setupLeds() {
+ Serial.println(F("Updating from setupleds"));
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
pinMode(coldPin, OUTPUT);
pinMode(warmPin, OUTPUT);
- Serial.println(F("Updating from setupleds"));
- updateleds();
}
void ledsloop(){
RGBCycle();
- if((printerVariables.finishstartms > 0 && millis() - printerVariables.finishstartms) >= 300000 && printerVariables.gcodeState == "FINISH"){
- printerVariables.finishstartms = 0;
- printerVariables.gcodeState = "IDLE";
- Serial.println(F("Updating from finishloop"));
+
+ // Turn off GREEN if... finished and Door OPENED or CLOSED in last 5 secs AND user wants Finish Indication enabled
+ // Can't use Boolean finished as printer defaults back to IDLE via MQTT
+ if((printerVariables.waitingForDoor && printerConfig.finishindication == true
+ && ((millis() - printerVariables.lastdoorClosems) < 6000 || (millis() - printerVariables.lastdoorOpenms) < 6000))){
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.println(F("Updating from finishloop after Door interaction - Starting IDLE timer"));
+ };
+ printerVariables.waitingForDoor = false;
+ printerVariables.inactivityStartms = millis();
+ updateleds();
+ }
+
+ //Need an trigger action to run updateleds() so lights turn off
+ //There is no change in the printer STATE, just monitoring the timer and triggering when over a threshhold
+ if(printerConfig.inactivityEnabled && (millis() - printerVariables.inactivityStartms) > printerConfig.inactivityTimeOut
+ && printerVariables.finished == false && printerVariables.inactivityLightsOff == false)
+ {
+ //Opening or Closing the Door will turn LEDs back on and restart the timer.
updateleds();
}
delay(10);
diff --git a/src/main.cpp b/src/main.cpp
index 4b02d71..202e6ed 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,54 +7,97 @@
#include "serialmanager.h"
#include "wifi-manager.h"
+void defaultcolors(){
+ Serial.println(F("Setting default customisable colors"));
+ strcpy(printerConfig.testRGB, "#3F3CFB"); //Violet
+ strcpy(printerConfig.wifiRGB, "#FFA500"); //Orange
+ strcpy(printerConfig.finishRGB, "#00FF00"); //Green
+ strcpy(printerConfig.pauseRGB, "#0000FF"); //Blue
+ strcpy(printerConfig.firstlayerRGB, "#0000FF"); //Blue
+ strcpy(printerConfig.nozzleclogRGB, "#0000FF"); //Blue
+ strcpy(printerConfig.hmsSeriousRGB, "#FF0000"); //Red
+ strcpy(printerConfig.hmsFatalRGB, "#FF0000"); //Red
+ strcpy(printerConfig.filamentRunoutRGB, "#FF0000"); //Red
+ strcpy(printerConfig.frontCoverRGB, "#FF0000"); //Red
+ strcpy(printerConfig.nozzleTempRGB, "#FF0000"); //Red
+ strcpy(printerConfig.bedTempRGB, "#FF0000"); //Red
+}
+
void setup(){
Serial.begin(115200);
delay(100);
Serial.println(F("Initializing"));
Serial.println(ESP.getFreeHeap());
+ defaultcolors();
setupLeds();
- tweenToColor(255,255,255,255,255,500);
- delay(2000);
- tweenToColor(255,0,0,0,0,500);
+ tweenToColor(255,255,255,255,255); //ALL LEDS ON
+ delay(1000);
+
+ tweenToColor(255,0,0,0,0); //RED
setupFileSystem();
loadFileSystem();
- delay(2000);
- tweenToColor(255,165,0,0,0,500);
+ delay(500);
+
+ tweenToColor(printerConfig.wifiRGB); //Customisable - Default is ORANGE
setupSerial();
if (strlen(globalVariables.SSID) == 0 || strlen(globalVariables.APPW) == 0) {
Serial.println(F("SSID or password is missing. Please configure both by going to: https://dutchdevelop.com/blled-configuration-setup/"));
- tweenToColor(255,0,255,0,0,500);
+ tweenToColor(255,0,255,0,0); //PINK
return;
}
-
- if (!connectToWifi()){
+
+ scanNetwork(); //Sets the MAC address for following connection attempt
+ if(!connectToWifi()){
return;
- };
- delay(2000);
- tweenToColor(0,0,255,0,0,500);
- setupWebserver();
+ }
- delay(2000);
+ tweenToColor(0,0,255,0,0); //BLUE
+ setupWebserver();
+ delay(500);
- tweenToColor(0,0,0,0,0,500);
+
+ tweenToColor(34,224,238,0,0); //CYAN
setupMqtt();
+ Serial.println();
Serial.println(F("BLLED Controller started"));
-
+ Serial.println();
+ tweenToColor(0,0,0,0,0,3000); //Fade to Black before starting
globalVariables.started = true;
}
void loop(){
serialLoop();
- if (globalVariables.started == true){
+ if(printerConfig.maintMode){
+ //Doesn't require monitoring of Wifi or MQTT if LEDs only need to be ON
+ webserverloop();
+ if(printerConfig.updateMaintenance) updateleds();
+ printerVariables.inactivityStartms = millis(); // Don't turn light off (due to inactivity) if in Maintenance Mode
+ }
+ else if (printerVariables.testcolorEnabled){
+ //Doesn't require monitoring of Wifi or MQTT if LEDs set to a custom color
+ webserverloop();
+ if(printerConfig.updateTestLEDS) ledsloop();
+ }
+ else if (globalVariables.started){
mqttloop();
webserverloop();
ledsloop();
+
if (WiFi.status() != WL_CONNECTED){
- Serial.println(F("Lost Connection, Reconnecting"));
+ Serial.println(F("Reconnecting to WiFi..."));
WiFi.disconnect();
+ delay(10);
WiFi.reconnect();
}
}
-}
\ No newline at end of file
+ if(printerConfig.rescanWiFiNetwork)
+ {
+ Serial.println(F("Web submitted refresh of Wifi Scan (assigning Strongest AP)"));
+ tweenToColor(printerConfig.wifiRGB); //Customisable - Default is ORANGE
+ scanNetwork(); //Sets the MAC address for following connection attempt
+ printerConfig.rescanWiFiNetwork = false;
+ updateleds();
+ }
+}
diff --git a/src/mqttmanager.h b/src/mqttmanager.h
index 4633a0c..ad2f4bf 100644
--- a/src/mqttmanager.h
+++ b/src/mqttmanager.h
@@ -3,9 +3,6 @@
#include
#include
-static int mqttbuffer = 32768;
-static int mqttdocument = 32768; //16384
-
#include
#include
#include
@@ -26,126 +23,256 @@ AutoGrowBufferStream stream;
unsigned long mqttattempt = (millis()-3000);
+//With a Default BLLED
+//Expected information when viewing MQTT status messages
+
+//gcode_state stg_cur BLLED LED control Comments
+//------------------------------------------------------------------------
+//IDLE -1 White Printer just powered on
+//RUNNING -1 White Printer sent print file
+//RUNNING 2 White PREHEATING BED
+//RUNNING 14 OFF (for Lidar) CLEANING NOZZLE
+//RUNNING 1 OFF (for Lidar) BED LEVELING
+//RUNNING 8 OFF (for Lidar) CALIBRATING EXTRUSION
+//RUNNING 0 White All the printing happens here
+//FINISH -1 Green After bed is lowered and filament retracted
+//FINISH -1 Green BLLED logic waits for a door interaction
+//FINISH -1 White After door interaction
+//FINISH -1 OFF Inactivity after 30mins
+
+
void connectMqtt(){
+ if(WiFi.status() != WL_CONNECTED){
+ //Abort MQTT connection attempt when no Wifi
+ return;
+ }
if (!mqttClient.connected() && (millis() - mqttattempt) >= 3000){
- Serial.println(F("Connecting to mqtt"));
+ Serial.println(F("Connecting to mqtt..."));
if (mqttClient.connect(clientId.c_str(),"bblp",printerConfig.accessCode)){
- Serial.println(F("MWTT connected, subscribing to topic:"));
+ Serial.print(F("MQTT connected, subscribing to MQTT Topic: "));
Serial.println(report_topic);
mqttClient.subscribe(report_topic.c_str());
printerVariables.online = true;
- Serial.println(F("Updating from mqtt connnection"));
+ printerVariables.disconnectMQTTms = 0;
+ Serial.println(F("Updating LEDs from MQTT connect"));
updateleds();
}else{
Serial.println(F("Failed to connect with error code: "));
- Serial.println(mqttClient.state());
- switch (mqttClient.state())
- {
- case -4: // MQTT_CONNECTION_TIMEOUT
- Serial.println(F("MQTT TIMEOUT"));
- break;
- case -2: // MQTT_CONNECT_FAILED
- Serial.println(F("MQTT CONNECT_FAILED"));
- break;
- case -3: // MQTT_CONNECTION_LOST
- Serial.println(F("MQTT CONNECTION_LOST"));
- break;
- case -1: // MQTT_DISCONNECTED
- Serial.println(F("MQTT DISCONNECTED"));
- break;
- case 1:
- break;
- case 2:
- break;
- case 3:
- break;
- case 4:
- break;
- case 5: // MQTT UNAUTHORIZED
- Serial.println(F("MQTT UNAUTHORIZED"));
- ESP.restart();
- break;
+ Serial.print(mqttClient.state());
+ Serial.print(F(" "));
+ ParseMQTTState(mqttClient.state());
+ if(mqttClient.state() == 5){
+ Serial.println(F("Restarting Device"));
+ delay(1000);
+ ESP.restart();
}
}
}
}
void ParseCallback(char *topic, byte *payload, unsigned int length){
- DynamicJsonDocument messageobject(mqttdocument);
+ JsonDocument messageobject;
+
+ JsonDocument filter;
+ //Rather than showing the entire message to Serial - grabbing only the pertinent bits for BLLED.
+ //Device Status
+ filter["print"]["command"] = true;
+ filter["print"]["fail_reason"] = true;
+ filter["print"]["gcode_state"] = true;
+ filter["print"]["print_gcode_action"] = true;
+ filter["print"]["print_real_action"] = true;
+ filter["print"]["hms"] = true;
+ filter["print"]["lights_report"] = true;
+ filter["print"]["home_flag"] = true;
+ filter["print"]["stg_cur"] = true;
+ filter["print"]["print_error"] = true;
+ filter["print"]["wifi_signal"] = true;
+
+ //Adding extra filters that looking interesting
+ //Could be useful for additional functionality that might be developed at a later date
+ //Color blend, the closer to 100% - I dunno
+
+ //Print Job Status
+ //filter["print"]["subtask_name"] = true; //Print Name
+ //filter["print"]["layer_num"] = true;
+ //filter["print"]["total_layer_num"] = true;
+ //filter["print"]["mc_percent"] = true;
+ //filter["print"]["mc_print_error_code"] = true;
+ //filter["print"]["mc_print_stage"] = true;
+ //filter["print"]["mc_print_sub_stage"] = true;
+ //filter["print"]["mc_remaining_time"] = true;
+
+ //Temperatures
+ //filter["print"]["bed_target_temper"] = true;
+ //filter["print"]["bed_temper"] = true;
+ //filter["print"]["nozzle_target_temper"] = true;
+ //filter["print"]["nozzle_temper"] = true;
+ //filter["print"]["chamber_temper"] = true;
- DynamicJsonDocument filter(128);
- filter["print"]["*"] = true;
- filter["camera"]["*"] = true;
-
auto deserializeError = deserializeJson(messageobject, payload, length, DeserializationOption::Filter(filter));
if (!deserializeError){
if (printerConfig.debuging){
- Serial.println(F("Mqtt message received,"));
- Serial.println(F("FreeHeap: "));
- Serial.print(ESP.getFreeHeap());
- Serial.println();
+ Serial.print(F("Mqtt message received, "));
+ Serial.print(F("FreeHeap: "));
+ Serial.println(ESP.getFreeHeap());
+ }
+
+ bool Changed = false;
+
+ if (messageobject["print"].containsKey("command")){
+ if (messageobject["print"]["command"].as() == "gcode_line"){
+ //gcode_line used a lot during print initialisations - Skip these
+ return;
+ }
+ }
+ if(messageobject.size() == 0)
+ {
+ //Null or Filtered essage that is not 'print' - Ignore
+ return;
}
+ //Output Filtered MQTT message
if (printerConfig.mqttdebug){
- Serial.println(F("Mqtt payload:"));
- Serial.println();
+ Serial.print(F("(Filtered) MQTT payload, "));
+ Serial.print(messageobject.size());
+ Serial.print(F(", "));
serializeJson(messageobject, Serial);
Serial.println();
}
- bool Changed = false;
+ //Check BBLP Stage
if (messageobject["print"].containsKey("stg_cur")){
- printerVariables.stage = messageobject["print"]["stg_cur"];
- Changed = true;
+ if (printerVariables.stage != messageobject["print"]["stg_cur"].as() ){
+ printerVariables.inactivityStartms = millis(); //restart idle timer
+ printerVariables.stage = messageobject["print"]["stg_cur"];
+
+ if (printerConfig.debugingchange || printerConfig.debuging){
+ Serial.print(F("MQTT update - stg_cur now: "));
+ Serial.println(printerVariables.stage);
+ }
+ Changed = true;
+ }
}else{
if (printerConfig.debuging){
- Serial.println(F("stg_cur not in message"));
+ Serial.println(F("MQTT stg_cur not in message"));
}
}
+ //Check BBLP GCode State
if (messageobject["print"].containsKey("gcode_state")){
- printerVariables.gcodeState = messageobject["print"]["gcode_state"].as();
- if (printerVariables.gcodeState == "FINISH"){
- if (printerVariables.finished == false){
+ String mqttgcodeState = messageobject["print"]["gcode_state"].as();
+
+ if(mqttgcodeState =="RUNNING" || mqttgcodeState =="PAUSE"){
+ //Never turn off light (due to idle timer) while in this state
+ printerVariables.inactivityStartms = millis();
+ }
+
+ // Onchange of gcodeState...
+ if(printerVariables.gcodeState != mqttgcodeState){
+ printerVariables.inactivityStartms = millis(); //restart idle timer
+
+ if(mqttgcodeState =="FINISH"){
printerVariables.finished = true;
- printerVariables.finishstartms = millis();
+ if(printerConfig.finishindication == true) printerVariables.waitingForDoor = true;
}
- }else{
- printerVariables.finished = false;
+ printerVariables.gcodeState = mqttgcodeState;
+
+ if (printerConfig.debugingchange || printerConfig.debuging){
+ Serial.print(F("MQTT update - gcode_state now: "));
+ Serial.println(printerVariables.gcodeState);
+ }
+ Changed = true;
}
- Changed = true;
}
+
if (messageobject["print"].containsKey("lights_report")) {
JsonArray lightsReport = messageobject["print"]["lights_report"];
for (JsonObject light : lightsReport) {
if (light["node"] == "chamber_light") {
- printerVariables.ledstate = light["mode"] == "on";
- Changed = true;
+ if(printerVariables.printerledstate != (light["mode"] == "on")){
+ printerVariables.printerledstate = light["mode"] == "on";
+ if (printerConfig.debugingchange || printerConfig.debuging){
+ Serial.print(F("MQTT chamber_light now: "));
+ Serial.println(printerVariables.printerledstate);
+ }
+ Changed = true;
+ }
}
}
}else{
if (printerConfig.debuging){
- Serial.println(F("lights_report not in message"));
+ Serial.println(F("MQTT lights_report not in message"));
}
}
-
+ //Bambu Health Management System (HMS)
if (messageobject["print"].containsKey("hms")){
+ String oldHMS = "";
+ oldHMS = printerVariables.parsedHMS;
+
printerVariables.hmsstate = false;
printerVariables.parsedHMS = "";
for (const auto& hms : messageobject["print"]["hms"].as()) {
if (ParseHMSSeverity(hms["code"]) != ""){
printerVariables.hmsstate = true;
printerVariables.parsedHMS = ParseHMSSeverity(hms["code"]);
+ int attrib = hms["attr"];
+ printerVariables.parsedHMSattrib = (attrib>>16);
+ }
+ }
+ if(oldHMS != printerVariables.parsedHMS){
+ printerVariables.inspectingFirstLayer = false;
+ if(printerVariables.parsedHMS == "Common" && printerVariables.parsedHMSattrib == 3072)
+ {
+ printerVariables.inspectingFirstLayer = true;
+ }
+
+
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("MQTT update - parsedHMS now: "));
+ if (printerVariables.parsedHMS.length() == 0) Serial.print(F("NULL"));
+ Serial.println(printerVariables.parsedHMS);
+ }
+ Changed = true;
+ }
+ }
+
+ if (messageobject["print"].containsKey("home_flag")){
+ //https://github.com/greghesp/ha-bambulab/blob/main/custom_components/bambu_lab/pybambu/const.py#L324
+
+ bool doorState = false;
+ long homeFlag = 0;
+ homeFlag = messageobject["print"]["home_flag"];
+ doorState = homeFlag >> 23; //shift left 23 to the Door bit
+ doorState = doorState & 1; // remove any bits above Door bit
+
+ if (printerVariables.doorOpen != doorState){
+ printerVariables.inactivityStartms = millis(); //restart idle timer
+
+ printerVariables.doorOpen = doorState;
+ printerVariables.inactivityLightsOff = false;
+ if (printerConfig.debugingchange)Serial.print(F("MQTT Door "));
+ if (printerVariables.doorOpen){
+ printerVariables.lastdoorOpenms = millis();
+ if (printerConfig.debugingchange) Serial.println(F("Opened"));
+ }
+ else{
+ if ((millis() - printerVariables.lastdoorClosems) < 6000){
+ printerVariables.doorSwitchenabled = true;
+ }
+ printerVariables.lastdoorClosems = millis();
+ if (printerConfig.debugingchange) Serial.println(F("Closed"));
}
+ Changed = true;
}
- Changed = true;
}
if (Changed == true){
- Serial.println(F("Updating from mqtt"));
+ if (printerConfig.debuging){
+ Serial.println(F("Change from mqtt"));
+ }
updateleds();
}
}else{
@@ -162,7 +289,7 @@ void mqttCallback(char *topic, byte *payload, unsigned int length){
void setupMqtt(){
clientId += String(random(0xffff), HEX);
- Serial.println(F("Setting up MQTT with ip: "));
+ Serial.print(F("Setting up MQTT with ip: "));
Serial.println(printerConfig.printerIP);
device_topic = String("device/") + printerConfig.serialNumber;
@@ -179,15 +306,27 @@ void setupMqtt(){
}
void mqttloop(){
+ if(WiFi.status() != WL_CONNECTED){
+ //Abort MQTT connection attempt when no Wifi
+ return;
+ }
if (!mqttClient.connected()){
printerVariables.online = false;
- Serial.println(F("Updating from connect to mqtt"));
- updateleds();
+ //Only sent the timer from the first instance of a MQTT disconnect
+ if(printerVariables.disconnectMQTTms == 0) {
+ printerVariables.disconnectMQTTms = millis();
+ //Record last time MQTT dropped connection
+ Serial.println(F("MQTT dropped during mqttloop"));
+ ParseMQTTState(mqttClient.state());
+ }
+ delay(500);
connectMqtt();
delay(32);
return;
}
-
+ else{
+ printerVariables.disconnectMQTTms = 0;
+ }
mqttClient.loop();
delay(10);
}
diff --git a/src/mqttparsingutility.h b/src/mqttparsingutility.h
index 8a906a4..1040314 100644
--- a/src/mqttparsingutility.h
+++ b/src/mqttparsingutility.h
@@ -19,5 +19,41 @@ String ParseHMSSeverity(int code){ // Provided by WolfWithSword
return "";
}
+void ParseMQTTState(int code){
+ switch (code)
+ {
+ case -4: // MQTT_CONNECTION_TIMEOUT
+ Serial.println(F("MQTT TIMEOUT"));
+ break;
+ case -3: // MQTT_CONNECTION_LOST
+ Serial.println(F("MQTT CONNECTION_LOST"));
+ break;
+ case -2: // MQTT_CONNECT_FAILED
+ Serial.println(F("MQTT CONNECT_FAILED"));
+ break;
+ case -1: // MQTT_DISCONNECTED
+ Serial.println(F("MQTT DISCONNECTED"));
+ break;
+ case 0: // MQTT_CONNECTED
+ Serial.println(F("MQTT CONNECTED"));
+ break;
+ case 1: // MQTT_CONNECT_BAD_PROTOCOL
+ Serial.println(F("MQTT BAD PROTOCOL"));
+ break;
+ case 2: // MQTT_CONNECT_BAD_CLIENT_ID
+ Serial.println(F("MQTT BAD CLIENT ID"));
+ break;
+ case 3: // MQTT_CONNECT_UNAVAILABLE
+ Serial.println(F("MQTT UNAVAILABLE"));
+ break;
+ case 4: // MQTT_CONNECT_BAD_CREDENTIALS
+ Serial.println(F("MQTT BAD CREDENTIALS"));
+ break;
+ case 5: // MQTT UNAUTHORIZED
+ Serial.println(F("MQTT UNAUTHORIZED"));
+ break;
+ }
+}
+
#endif
\ No newline at end of file
diff --git a/src/serialmanager.h b/src/serialmanager.h
index 9de40c7..3d4de29 100644
--- a/src/serialmanager.h
+++ b/src/serialmanager.h
@@ -14,12 +14,12 @@ void setupSerial(){
void serialLoop(){
if (Serial.available() > 0) {
String input = Serial.readStringUntil('\n');
- DynamicJsonDocument doc(256);
+ JsonDocument doc;
deserializeJson(doc, input);
if (doc.containsKey("ssid") && doc.containsKey("pass")) {
- Serial.print("SSID ");
+ Serial.print(F("SSID "));
Serial.println(doc["ssid"].as());
- Serial.print("PASS ");
+ Serial.print(F("PASS "));
Serial.println(doc["pass"].as());
Serial.println(doc["printerip"].as());
@@ -34,6 +34,8 @@ void serialLoop(){
strcpy(printerConfig.serialNumber, doc["printerserial"]);
saveFileSystem();
+ Serial.println(F("Restarting Device"));
+ delay(1000);
ESP.restart();
}
diff --git a/src/types.h b/src/types.h
index 6b599d3..6ca5fa0 100644
--- a/src/types.h
+++ b/src/types.h
@@ -8,13 +8,31 @@ extern "C"
typedef struct PrinterVaraiblesStruct{
String parsedHMS = "";
- String gcodeState = "IDLE";
+ int parsedHMSattrib = 0;
+ String gcodeState = "FINISH"; //Initialised to Finish so the logic doesn't
+ //assume a Print has just finished and needs
+ //to wait for a door interaction to continue
int stage = 0;
- bool ledstate = true;
+ bool testcolorEnabled = false;
+ bool printerledstate = true;
bool hmsstate = false;
bool online = false;
bool finished = false;
- unsigned long finishstartms;
+ bool initalisedLEDs = false;
+ bool inspectingFirstLayer = false;
+ //Time since
+ unsigned long disconnectMQTTms = 0;
+ //InactivityLightsOff Timer and status
+ bool inactivityLightsOff = false; // Are the lights out due to inactivity Timeout?
+ unsigned long inactivityStartms = 0; // Time the inactivity countdown is measured from
+
+ //Door Monitoring
+ bool doorOpen = false; // Current State of Door
+ bool doorSwitchenabled = false; // Has door been closed twice within 6 seconds?
+ bool waitingForDoor = false; // Are we waiting for the door to be actuated?
+ unsigned long lastdoorClosems = 0; // Last time door was opened
+ unsigned long lastdoorOpenms = 0; // Last time door was closed
+
} PrinterVariables;
@@ -23,7 +41,7 @@ extern "C"
typedef struct GlobalVariablesStruct{
char SSID[32];
char APPW[32];
- String FWVersion = "EXPERIMENTAL 25.2.24";
+ String FWVersion = "EXPERIMENTAL 16.3.24";
String Host = "BLLED";
bool started = false;
} GlobalVariables;
@@ -32,16 +50,46 @@ extern "C"
typedef struct PrinterConfigStruct
{
- int brightness = 100;
- bool replicatestate = true;
- bool errordetection = true;
- bool finishindication = true;
- bool debuging = true;
- bool mqttdebug = true;
- bool turbo = false;
- char printerIP[16];
- char accessCode[9];
- char serialNumber[16];
+ char printerIP[16]; //BBLP IP Address - used for MQTT reports
+ char accessCode[9]; //BBLP Access Code - used for MQTT reports
+ char serialNumber[16]; //BBLP Serial Number - used for MQTT reports
+
+ char BSSID[18]; //Nominated AP to connect to (Useful if multiple accesspoints with same name)
+ int brightness = 100; //Brightness of LEDS
+ bool rescanWiFiNetwork = false; //Scans available WiFi networks for strongest signal
+ // BLLED Settings
+ bool replicatestate = true; //LED will be on if the BBPL Light is on
+ bool errordetection = true; //Utilises Error Colors when BBLP give an error
+ bool finishindication = true; //Utilises Finish Color when print ends successfully
+ bool lidarLightsOff = true; //For X1C owners - option to turn off if you have a P1P with no Lidar.
+ bool inactivityEnabled = true;
+ int inactivityTimeOut = 1800000;// 1800000 = 30 mins
+ bool discoMode = false; //Cycles through RGB colors slowly for 'pretty' timelapse movie
+ bool maintMode = false; //White lights on, even if printer is unpowered
+ bool updateMaintenance = false; //When updateleds() is run, should the Maintenance LEDS be set?
+ // Debugging
+ bool debuging = false; //Debugging for all interactions through functions
+ bool debugingchange = true; //Default debugging level - to shows onChange
+ bool mqttdebug = false; //Writes each packet from BBLP to the serial log
+ bool debugwifi = false; //Changes LED to a color range that represents WiFi signal Strength
+ // Test - Fixed LED Colors
+ char testRGB[8]; //Test Color (RGB only)
+ int testwarmwhite = 100; //Testing just the Warm White LED line
+ int testcoldwhite = 100; //Testing just the Cold White LED line
+ bool updateTestLEDS = false; //When updateleds() is run, should the TEST LEDS be set?
+ // Customise LED Colors
+ char wifiRGB[8]; //These need to be 8 char: '#' + 123456 + end char '/0'
+ char finishRGB[8];
+ char pauseRGB[8];
+ char firstlayerRGB[8];
+ char nozzleclogRGB[8];
+ char hmsSeriousRGB[8];
+ char hmsFatalRGB[8];
+ char filamentRunoutRGB[8];
+ char frontCoverRGB[8];
+ char nozzleTempRGB[8];
+ char bedTempRGB[8];
+
//char webpagePassword[8];
} PrinterConfig;
diff --git a/src/web-server.h b/src/web-server.h
index e15e0ab..f249646 100644
--- a/src/web-server.h
+++ b/src/web-server.h
@@ -13,6 +13,8 @@
WebServer webServer(80);
+
+
#include "www/setupPage.h"
bool isAuthorized() {
@@ -25,28 +27,75 @@ void handleSetup(){
return;
}
webServer.sendHeader(F("Content-Encoding"), F("gzip"));
- webServer.send_P(200, "text/html", (const char*)setupPage_html_gz, (int)setupPage_html_gz_len);
+ webServer.send_P(200, "text/html", (const char*)setuppage_html_gz, (int)setuppage_html_gz_len);
}
void submitSetup(){
+ bool newBSSID = false;
if (webServer.args() > 0) {
-
+ if( strcmp(printerConfig.BSSID,webServer.arg("apMAC").c_str()) != 0 ){
+ newBSSID = true;
+ }
strcpy(printerConfig.printerIP,webServer.arg("ip").c_str());
strcpy(printerConfig.accessCode,webServer.arg("code").c_str());
strcpy(printerConfig.serialNumber,webServer.arg("id").c_str());
- printerConfig.turbo = webServer.arg("turbo") == "on";
+
+ strcpy(printerConfig.BSSID,webServer.arg("apMAC").c_str());
+ printerConfig.brightness = webServer.arg("brightnessslider").toInt();
+ printerConfig.rescanWiFiNetwork = webServer.arg("rescanWiFiNetwork") == "on";
+ // BLLED Settings
printerConfig.replicatestate = webServer.arg("replicateLedState") == "on";
printerConfig.errordetection = webServer.arg("errorDetection") == "on";
printerConfig.finishindication = webServer.arg("finishIndication") == "on";
+ printerConfig.lidarLightsOff = webServer.arg("lidarLightsOff") == "on";
+ printerConfig.inactivityEnabled = webServer.arg("inactivityEnabled") == "on";
+ printerConfig.inactivityTimeOut = (webServer.arg("inactivityMins").toInt() * 60000);
+ if(printerConfig.maintMode != (webServer.arg("maintMode") == "on"))
+ {
+ printerConfig.maintMode = webServer.arg("maintMode") == "on";
+ printerConfig.updateMaintenance = printerConfig.maintMode;
+ if(printerConfig.maintMode && printerConfig.debugingchange){
+ Serial.println(F("Maintence Mode is ON"));
+ Serial.println(F("**No MQTT msgs, TEST colors or Wifi strength visualisation**"));
+ Serial.println();
+ }
+ }
+
+ printerConfig.discoMode = webServer.arg("discoMode") == "on";
printerConfig.debuging = webServer.arg("debuging") == "on";
+ printerConfig.debugingchange = webServer.arg("debugingchange") == "on";
printerConfig.mqttdebug = webServer.arg("mqttdebug") == "on";
- printerConfig.brightness = webServer.arg("brightnessslider").toInt();
+ // Test - Fixed LED Colors
+ printerVariables.testcolorEnabled = !printerConfig.replicatestate;
+ printerConfig.updateTestLEDS = !printerConfig.replicatestate;
+ strcpy(printerConfig.testRGB,webServer.arg("testRGB").c_str());
+ printerConfig.testcoldwhite = webServer.arg("cw_slider").toInt();
+ printerConfig.testwarmwhite = webServer.arg("ww_slider").toInt();
+
+ printerConfig.debugwifi = webServer.arg("debugwifi") == "on";
+ // Customise LED Colors
+ strcpy(printerConfig.wifiRGB,webServer.arg("wifiRGB").c_str());
+ strcpy(printerConfig.finishRGB, webServer.arg("finishRGB").c_str());
+ strcpy(printerConfig.pauseRGB, webServer.arg("pauseRGB").c_str());
+ strcpy(printerConfig.firstlayerRGB, webServer.arg("firstlayerRGB").c_str());
+ strcpy(printerConfig.nozzleclogRGB, webServer.arg("nozzleclogRGB").c_str());
+ strcpy(printerConfig.hmsSeriousRGB, webServer.arg("hmsSeriousRGB").c_str());
+ strcpy(printerConfig.hmsFatalRGB, webServer.arg("hmsFatalRGB").c_str());
+ strcpy(printerConfig.filamentRunoutRGB, webServer.arg("filamentRunoutRGB").c_str());
+ strcpy(printerConfig.frontCoverRGB, webServer.arg("frontCoverRGB").c_str());
+ strcpy(printerConfig.nozzleTempRGB, webServer.arg("nozzleTempRGB").c_str());
+ strcpy(printerConfig.bedTempRGB, webServer.arg("bedTempRGB").c_str());
saveFileSystem();
- Serial.println(F("Updating from webpage"));
+ Serial.println(F("Updating LEDS from webpage form submit"));
updateleds();
handleSetup();
-
+ if(newBSSID)
+ {
+ Serial.println(F("New MAC address (BSSID) assigned. Restarting..."));
+ delay(1000);
+ ESP.restart();
+ }
}
}
@@ -56,18 +105,45 @@ void handleGetConfig(){
return;
}
- DynamicJsonDocument doc(300);
- doc["brightness"] = printerConfig.brightness;
- doc["turbo"] = printerConfig.turbo;
+ JsonDocument doc;
doc["ip"] = printerConfig.printerIP;
doc["code"] = printerConfig.accessCode;
doc["id"] = printerConfig.serialNumber;
+
+ doc["apMAC"] = printerConfig.BSSID;
+ doc["brightness"] = printerConfig.brightness;
+ // BLLED Settings
doc["replicateled"] = printerConfig.replicatestate;
doc["errordetection"] = printerConfig.errordetection;
doc["finishindication"] = printerConfig.finishindication;
+ doc["lidarLightsOff"] = printerConfig.lidarLightsOff;
+ doc["inactivityEnabled"] = printerConfig.inactivityEnabled;
+ doc["inactivityMins"] =(int)( printerConfig.inactivityTimeOut / 60000);
+ doc["discoMode"] = printerConfig.discoMode;
+ doc["maintMode"] = printerConfig.maintMode;
+ // Debugging
doc["debuging"] = printerConfig.debuging;
+ doc["debugingchange"] = printerConfig.debugingchange;
doc["mqttdebug"] = printerConfig.mqttdebug;
-
+ // Test - Fixed LED Colors
+ doc["testRGB"] = printerConfig.testRGB;
+ doc["cw_slider"] = printerConfig.testcoldwhite;
+ doc["ww_slider"] = printerConfig.testwarmwhite;
+
+ doc["debugwifi"] = printerConfig.debugwifi;
+ // Customise LED Colors
+ doc["wifiRGB"] = printerConfig.wifiRGB;
+ doc["finishRGB"] = printerConfig.finishRGB;
+ doc["pauseRGB"] = printerConfig.pauseRGB;
+ doc["firstlayerRGB"] = printerConfig.firstlayerRGB;
+ doc["nozzleclogRGB"] = printerConfig.nozzleclogRGB;
+ doc["hmsSeriousRGB"] = printerConfig.hmsSeriousRGB;
+ doc["hmsFatalRGB"] = printerConfig.hmsFatalRGB;
+ doc["filamentRunoutRGB"] = printerConfig.filamentRunoutRGB;
+ doc["frontCoverRGB"] = printerConfig.frontCoverRGB;
+ doc["nozzleTempRGB"] = printerConfig.nozzleTempRGB;
+ doc["bedTempRGB"] = printerConfig.bedTempRGB;
+
const char* firmwareVersionChar = globalVariables.FWVersion.c_str();
doc["firmwareversion"] = firmwareVersionChar;
@@ -94,6 +170,8 @@ void setupWebserver(){
webServer.on("/update", HTTP_POST, []() {
webServer.sendHeader("Connection", "close");
webServer.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
+ Serial.println(F("Restarting Device"));
+ delay(1000);
ESP.restart();
}, []() {
HTTPUpload& upload = webServer.upload();
@@ -119,6 +197,7 @@ void setupWebserver(){
webServer.begin();
Serial.println(F("Webserver started"));
+ Serial.println();
}
void webserverloop(){
diff --git a/src/wifi-manager.h b/src/wifi-manager.h
index 6550d57..5895198 100644
--- a/src/wifi-manager.h
+++ b/src/wifi-manager.h
@@ -12,42 +12,78 @@ bool shouldSaveConfig = true;
int connectionAttempts = 0;
void configModeCallback() {
- Serial.println("Entered config mode");
- Serial.print("AP IP address: ");
+ Serial.println(F("Entered config mode"));
+ Serial.print(F("AP IP address: "));
Serial.println(WiFi.softAPIP());
}
+int str2mac(const char* mac, uint8_t* values){
+ if( 6 == sscanf( mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",&values[0], &values[1], &values[2],&values[3], &values[4], &values[5] ) ){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
bool connectToWifi(){
Serial.println(F("-------------------------------------"));
- WiFi.mode(WIFI_STA);
+ WiFi.mode(WIFI_STA); //ESP32 connects to an access point
delay(10);
- while (WiFi.status() != WL_CONNECTED) {
+
+ if(strlen(printerConfig.BSSID) == 0){
WiFi.begin(globalVariables.SSID, globalVariables.APPW);
- delay(1000);
-
- wl_status_t status = WiFi.status();
- switch (status)
- {
- case WL_IDLE_STATUS:
- Serial.print(F("Connecting to WIFI.. Attempt #"));
- Serial.print(connectionAttempts);
- Serial.print(F(" SSID: "));
- Serial.print(globalVariables.SSID);
- Serial.print(F(" APPW: "));
- Serial.println(globalVariables.APPW);
- break;
- case WL_NO_SSID_AVAIL:
- Serial.print(F("Bad WiFi credentials"));
- return false;
- case WL_CONNECT_FAILED:
- case WL_DISCONNECTED:
- Serial.print(F("Check your WiFi credentials."));
- return false;
- default:
- break;
+ }
+ else{
+ // Reference https://stackoverflow.com/questions/70415075/esp32-select-one-from-multiple-wifi-ap-with-same-name-ssid
+ uint8_t bssid[6] = {0};
+
+ //Function to convert String MAC address to 6 byte array
+ if(str2mac(printerConfig.BSSID,bssid)){
+ WiFi.begin(globalVariables.SSID, globalVariables.APPW, 0, bssid);
+ }
+ else{
+ if (printerConfig.debuging || printerConfig.debugingchange){
+ Serial.print(F("Parsing MAC Address Failed, reverting to "));
+ Serial.println(globalVariables.SSID);
+ }
+ WiFi.begin(globalVariables.SSID, globalVariables.APPW);
}
+ }
+
+ wl_status_t status = WiFi.status();
+
+ while (status != WL_CONNECTED) {
- delay(10000); // Giving enough time to connect
+ if(status != WiFi.status()){
+ status = WiFi.status();
+ switch (status)
+ {
+ case WL_IDLE_STATUS:
+ Serial.print(F("Connecting to WIFI.. Attempt #"));
+ Serial.println(connectionAttempts);
+ Serial.print(F(" SSID: "));
+ Serial.print(globalVariables.SSID);
+ Serial.print(F(" APPW: "));
+ Serial.print(globalVariables.APPW);
+ if(strlen(printerConfig.BSSID) > 0){
+ Serial.print(F(" BSSID: "));
+ Serial.print(globalVariables.SSID);
+ }
+ Serial.println();
+ break;
+ case WL_NO_SSID_AVAIL:
+ Serial.print(F("Bad WiFi credentials"));
+ return false;
+ case WL_CONNECT_FAILED:
+ Serial.print(F("Connect Failed."));
+ break;
+ case WL_DISCONNECTED:
+ Serial.print(F("Disconnected. (Check low RSSI)"));
+ default:
+ break;
+ }
+ }
+ delay(1000); // Giving time to connect
connectionAttempts++;
}
@@ -59,16 +95,81 @@ bool connectToWifi(){
WiFi.setTxPower(WIFI_POWER_19_5dBm); // https://github.com/G6EJD/ESP32-8266-Adjust-WiFi-RF-Power-Output/blob/main/README.md
#endif
- delay(1000);
- int signalStrength = WiFi.RSSI();
- Serial.println(F("Connected To Wifi With Signal Strength: "));
- Serial.println(signalStrength);
- Serial.println();
- delay(10);
- Serial.print("IP_ADDRESS:"); // Unique identifier for the IP address
+ Serial.print(F("Connected To Wifi Access Point: "));
+ Serial.println(globalVariables.SSID);
+ Serial.print(F("Specific BSSID: ")); //MAC address of connected AP
+ Serial.println(WiFi.BSSIDstr());
+ Serial.print(F("RSSI (Signal Strength): "));
+ Serial.println(WiFi.RSSI());
+ Serial.print(F("IP_ADDRESS: ")); // Unique identifier for the IP address
Serial.println(WiFi.localIP());
-
+ Serial.println();
return true;
};
+void scanNetwork()
+{
+ //Reference / Credit - https://www.esp32.com/viewtopic.php?t=18979#p70299
+ int bestRSSI = -200;
+ String bestBSSID = "";
+
+ Serial.println(F("Wifi network scan start"));
+ int n = WiFi.scanNetworks();
+ Serial.println(F("Network scan complete"));
+
+ if (n == 0) {
+ Serial.println(F("No wifi networks found :("));
+ } else {
+ Serial.print(n); // Count
+ Serial.println(F(" Wifi networks found"));
+ Serial.println(F("-------------------------------------------------------------------------"));
+ for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found
+ Serial.print(i + 1);
+ Serial.print(F(": "));
+ Serial.print(WiFi.SSID(i));
+ Serial.print(F(" ("));
+ Serial.print(WiFi.RSSI(i));
+ Serial.print(F("dBm, "));
+ if (WiFi.RSSI(i) < -50) Serial.print(F(" ")); //Spacing... because I just can't look at the results when misaligned.
+ Serial.print(constrain(2 * (WiFi.RSSI(i) + 100), 0, 100));
+ Serial.print(F("%) "));
+ Serial.print(F("BSSID: "));
+ Serial.print(WiFi.BSSIDstr(i));
+ Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " open" : " encrypted");
+
+ if(WiFi.SSID(i) == globalVariables.SSID && WiFi.RSSI(i) > bestRSSI)
+ {
+ bestBSSID = WiFi.BSSIDstr(i);
+ bestRSSI = WiFi.RSSI(i);
+ }
+ delay(10);
+ }
+ Serial.println();
+ if(printerConfig.BSSID == bestBSSID.c_str()){
+ Serial.print(F("BSSID already set to: "));
+ Serial.print(printerConfig.BSSID);
+ }
+ else{
+ if(strlen(printerConfig.BSSID) == 0 || printerConfig.rescanWiFiNetwork){
+ strcpy(printerConfig.BSSID,bestBSSID.c_str());
+ Serial.print(F("Saving strongest AP for: "));
+ Serial.println(globalVariables.SSID);
+ Serial.print(F("Strongest BSSID (MAC Address): "));
+ Serial.print(printerConfig.BSSID);
+ }
+ else{
+ Serial.print(F("Ignoring strongest AP for: "));
+ Serial.println(globalVariables.SSID);
+ Serial.print(F("Using alrady saved BSSID (MAC Address): "));
+ Serial.print(printerConfig.BSSID);
+ }
+ Serial.print(F(" RSSI (Signal Strength): "));
+ Serial.print(bestRSSI);
+ Serial.println(F("dBm"));
+ }
+ }
+ Serial.println();
+}
+
+
#endif
diff --git a/src/www/Icon square.png b/src/www/Icon-square.png
old mode 100755
new mode 100644
similarity index 100%
rename from src/www/Icon square.png
rename to src/www/Icon-square.png
diff --git a/src/www/setupPage.h b/src/www/setupPage.h
index c66260f..8b9381b 100644
--- a/src/www/setupPage.h
+++ b/src/www/setupPage.h
@@ -1,156 +1,278 @@
-//File: setuppage.html.gz, Size: 2403
//https://mischianti.org/online-converter-file-to-cpp-gzip-byte-array-3/
-#define setupPage_html_gz_len 2409
-const uint8_t setupPage_html_gz[] PROGMEM = {
-0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xED, 0x5A, 0xEB, 0x73, 0xDB, 0x36,
-0x12, 0xFF, 0x9E, 0xBF, 0x02, 0x51, 0x27, 0xA1, 0x3C, 0x0E, 0x45, 0xC9, 0x8A, 0xDD, 0x54, 0x91,
-0x34, 0x93, 0xF8, 0x91, 0xDA, 0x75, 0x1A, 0xD7, 0x76, 0x32, 0xB9, 0x74, 0xFA, 0x01, 0x22, 0x41,
-0x11, 0x36, 0x49, 0x30, 0x00, 0x68, 0x49, 0xB9, 0xE6, 0x7F, 0xBF, 0x05, 0x40, 0xBD, 0x40, 0x52,
-0x7E, 0x34, 0x97, 0x9B, 0xC9, 0x9C, 0x9D, 0x58, 0x24, 0xB0, 0xDC, 0xC7, 0x6F, 0x17, 0xBB, 0x0B,
-0x50, 0xFD, 0xC7, 0x07, 0xEF, 0xF6, 0x2F, 0xFF, 0x75, 0x76, 0x88, 0x22, 0x99, 0xC4, 0xC3, 0x47,
-0x7D, 0xF3, 0x01, 0x9F, 0x04, 0x07, 0xC3, 0x47, 0x08, 0x7E, 0xFA, 0x31, 0x4D, 0xAF, 0x11, 0x27,
-0xF1, 0xC0, 0x11, 0x72, 0x16, 0x13, 0x11, 0x11, 0x22, 0x1D, 0x14, 0x71, 0x12, 0x0E, 0x9C, 0x48,
-0xCA, 0x4C, 0xF4, 0x3C, 0xCF, 0x0F, 0xD2, 0x2B, 0xD1, 0xF2, 0x63, 0x96, 0x07, 0x61, 0x8C, 0x39,
-0x69, 0xF9, 0x2C, 0xF1, 0xF0, 0x15, 0x9E, 0x7A, 0x31, 0x1D, 0x09, 0x2F, 0x64, 0xA9, 0x74, 0xF1,
-0x84, 0x08, 0x96, 0x10, 0x6F, 0xB7, 0xD5, 0xD9, 0x6D, 0x75, 0x3D, 0x5F, 0x08, 0x0F, 0xC7, 0x71,
-0x2B, 0xA1, 0x69, 0x0B, 0xAE, 0x1D, 0x44, 0x53, 0x49, 0xC6, 0x9C, 0xCA, 0x19, 0x08, 0x8A, 0xF0,
-0x6E, 0x67, 0xC7, 0xA5, 0xD3, 0xF8, 0xDD, 0xA7, 0x93, 0x69, 0xFC, 0x02, 0x5F, 0x75, 0xF6, 0xBF,
-0xB4, 0x93, 0xDF, 0xAE, 0x66, 0x47, 0x97, 0x27, 0x7F, 0x4C, 0x3D, 0xB1, 0xFD, 0x7E, 0x6F, 0xC2,
-0xDA, 0x6C, 0xEF, 0x6C, 0x7B, 0xFF, 0xD3, 0xD9, 0xF9, 0xC9, 0xC7, 0xED, 0xF1, 0x17, 0xD2, 0x3D,
-0x89, 0x5E, 0x1C, 0x71, 0xE6, 0x25, 0x97, 0xB3, 0x53, 0xBE, 0xCB, 0xBD, 0x0F, 0xD3, 0xED, 0xFC,
-0xC3, 0xCF, 0x27, 0x2F, 0xCE, 0x6F, 0xCE, 0xC3, 0x4F, 0xD9, 0xEE, 0xF6, 0xC7, 0x5F, 0x42, 0x7A,
-0xF3, 0xE6, 0xE7, 0x57, 0x83, 0x81, 0x83, 0x7C, 0xCE, 0x84, 0x60, 0x9C, 0x8E, 0x69, 0x3A, 0x70,
-0x70, 0xCA, 0xD2, 0x59, 0xC2, 0x72, 0xD0, 0x01, 0x8C, 0x22, 0x9C, 0x13, 0x9E, 0xB1, 0x98, 0xFA,
-0xA0, 0x48, 0xCA, 0xDC, 0xF9, 0x90, 0x83, 0xBC, 0x02, 0x10, 0x0D, 0x83, 0xB9, 0x56, 0x3F, 0x23,
-0x16, 0xCC, 0xD0, 0xBF, 0x17, 0xB7, 0x7A, 0x08, 0xFB, 0xD7, 0x63, 0xCE, 0xF2, 0x34, 0x70, 0x7D,
-0x16, 0x33, 0xDE, 0x43, 0x3F, 0x85, 0x1D, 0xF5, 0xFB, 0x72, 0x8D, 0x4C, 0xC3, 0x12, 0xE2, 0x84,
-0xC6, 0xB3, 0x1E, 0x7A, 0xC5, 0x29, 0x8E, 0x9F, 0x21, 0x81, 0x53, 0xE1, 0x0A, 0xC2, 0x69, 0xB8,
-0xA4, 0xFD, 0xBA, 0xB8, 0x02, 0x5C, 0x53, 0x89, 0x69, 0x4A, 0xB8, 0x25, 0x31, 0xA0, 0x22, 0x8B,
-0x31, 0xB0, 0x09, 0x63, 0x32, 0xB5, 0xA4, 0xC0, 0x88, 0x1B, 0x50, 0x4E, 0x7C, 0x49, 0x59, 0xDA,
-0x43, 0xA0, 0x51, 0x9E, 0xA4, 0xEB, 0x34, 0x57, 0xB9, 0x90, 0x34, 0x9C, 0xB9, 0x8A, 0x3D, 0x49,
-0x25, 0x10, 0xC1, 0x5F, 0xC2, 0xD7, 0x89, 0x70, 0x4C, 0xC7, 0xA9, 0x4B, 0x25, 0x49, 0x44, 0x35,
-0x41, 0x44, 0xE8, 0x38, 0x82, 0x87, 0x3B, 0xED, 0xF6, 0x4D, 0x54, 0xA9, 0x7E, 0xCC, 0xC6, 0xCC,
-0x7D, 0x80, 0x0D, 0x1B, 0x45, 0x5B, 0xFC, 0x2D, 0xAE, 0x13, 0x1A, 0xC8, 0x48, 0xEB, 0x94, 0x4D,
-0x6B, 0xD5, 0xB5, 0xA7, 0x12, 0xCC, 0x21, 0x34, 0x5C, 0x6E, 0x08, 0x76, 0xD6, 0xE6, 0x6D, 0x73,
-0x24, 0x99, 0x4A, 0x4B, 0xA6, 0x76, 0xAC, 0xA0, 0x5F, 0x48, 0x0F, 0x75, 0xF7, 0x6C, 0xDE, 0x7A,
-0x72, 0x52, 0xC8, 0x1E, 0xB1, 0x38, 0xA8, 0x64, 0x1D, 0x32, 0x9E, 0xD4, 0x22, 0x55, 0x8E, 0xAF,
-0x49, 0x04, 0xE0, 0xAC, 0xCB, 0xC9, 0x70, 0x10, 0xD0, 0x74, 0x6C, 0xAB, 0xAF, 0x9F, 0x67, 0x3C,
-0x20, 0xDC, 0xE5, 0x38, 0xA0, 0xB9, 0x50, 0x00, 0x94, 0x09, 0xA6, 0x2E, 0x2C, 0xC2, 0x80, 0x4D,
-0x7A, 0xA8, 0x0D, 0xBF, 0x8A, 0x02, 0xF1, 0xF1, 0x08, 0x37, 0xDB, 0xCF, 0x50, 0xF1, 0xAF, 0xD5,
-0xDD, 0x7A, 0x59, 0x85, 0xF4, 0x5E, 0xFB, 0x49, 0x25, 0x98, 0x92, 0x65, 0xF5, 0x50, 0xC6, 0x78,
-0x44, 0xE2, 0xBA, 0x78, 0x18, 0xC5, 0xCC, 0xBF, 0xAE, 0x94, 0x05, 0xAE, 0xAB, 0x16, 0x36, 0x62,
-0x52, 0xB2, 0xA4, 0x87, 0x76, 0xEF, 0x81, 0xFE, 0x62, 0xDA, 0x78, 0xAE, 0x53, 0xF2, 0xDC, 0x7C,
-0x2D, 0x77, 0xBB, 0xDD, 0x2A, 0x1B, 0x68, 0x9A, 0xE5, 0xF2, 0x4F, 0x39, 0xCB, 0xC8, 0xC0, 0x51,
-0x41, 0xE1, 0xFC, 0x55, 0x1B, 0x8A, 0x4F, 0x6A, 0x5C, 0x55, 0xE5, 0x89, 0x35, 0x57, 0x95, 0xEC,
-0x31, 0xF3, 0xF0, 0x24, 0x38, 0x48, 0x40, 0xD6, 0x0A, 0xD0, 0x4F, 0xBE, 0xEF, 0x6F, 0xC4, 0xA4,
-0x1C, 0x0F, 0xB5, 0x56, 0x57, 0x1B, 0x27, 0xF2, 0x51, 0x42, 0xCB, 0xE6, 0x55, 0x64, 0xBD, 0xE7,
-0xFB, 0xAF, 0x8E, 0x76, 0xDB, 0x95, 0x28, 0x6E, 0x8A, 0xD8, 0x87, 0xC3, 0x00, 0xA9, 0xDC, 0x62,
-0xEA, 0xE7, 0x5C, 0x28, 0x79, 0x19, 0xA3, 0xE5, 0x8C, 0x55, 0x1F, 0x9A, 0x1B, 0x61, 0x59, 0x4C,
-0xDE, 0xB6, 0x8C, 0x47, 0x39, 0x40, 0x9E, 0xFE, 0x1F, 0xA7, 0x5B, 0xD3, 0x9D, 0x64, 0xE3, 0x71,
-0x4C, 0xBE, 0x79, 0x69, 0x58, 0xD1, 0x7D, 0x1E, 0xFD, 0x9D, 0xBA, 0x64, 0x5E, 0xA8, 0x50, 0x95,
-0x89, 0xD6, 0xCB, 0xC1, 0x6D, 0x1C, 0xC4, 0x84, 0x4A, 0x3F, 0xB2, 0x58, 0x64, 0x4C, 0x50, 0x53,
-0x7F, 0xA1, 0x95, 0xC2, 0x92, 0xDE, 0x58, 0xF0, 0x2F, 0x2C, 0xA4, 0x29, 0x34, 0x5C, 0xC4, 0xAD,
-0xCF, 0x79, 0x7B, 0xB5, 0x85, 0xAC, 0xFB, 0xFC, 0x4E, 0x8A, 0xE9, 0xA5, 0x6C, 0xA9, 0xC7, 0x32,
-0xEC, 0x43, 0xEB, 0x05, 0xD9, 0xBE, 0x52, 0x66, 0xBB, 0x5A, 0x60, 0xBB, 0x52, 0x9A, 0x80, 0x2C,
-0x54, 0xF2, 0xE0, 0xD2, 0x7E, 0x3C, 0x82, 0x3C, 0x95, 0xDB, 0x31, 0xBD, 0x31, 0xFC, 0x74, 0xDC,
-0x59, 0x3A, 0xC4, 0x24, 0x94, 0xA5, 0x41, 0x5E, 0xD2, 0x4B, 0xFD, 0xCC, 0x5D, 0x6F, 0x0F, 0x97,
-0xD7, 0x61, 0x29, 0x75, 0x42, 0xE4, 0x8E, 0xAE, 0xA9, 0x74, 0x25, 0x87, 0xBE, 0xAC, 0x30, 0xA0,
-0xF5, 0x5C, 0x58, 0xEA, 0x6D, 0x9A, 0xB4, 0x56, 0x64, 0xAD, 0x8F, 0x0C, 0x6A, 0xBD, 0x11, 0x81,
-0xCA, 0x4F, 0xEE, 0x0B, 0xDE, 0xBC, 0x6D, 0x73, 0x9C, 0x6A, 0x47, 0xED, 0x94, 0x96, 0x65, 0xE1,
-0xD8, 0xF2, 0x84, 0xC1, 0xF5, 0x79, 0x39, 0x71, 0x18, 0x0C, 0xCB, 0x13, 0x77, 0xE9, 0x45, 0xBE,
-0x39, 0x8C, 0xBB, 0xAB, 0x25, 0xD4, 0xAA, 0x52, 0x3D, 0x3F, 0x22, 0xFE, 0x35, 0x09, 0xD0, 0x76,
-0x4D, 0x2C, 0x56, 0x38, 0x7E, 0xA7, 0xF3, 0xCB, 0xDE, 0x51, 0x7D, 0x55, 0xEF, 0x85, 0xCC, 0xCF,
-0x45, 0x3D, 0x43, 0xBB, 0x5D, 0x82, 0x62, 0x7C, 0x2B, 0xCB, 0x92, 0x96, 0xD5, 0xBE, 0x5F, 0x83,
-0x4E, 0x75, 0x85, 0x3D, 0x03, 0x14, 0x24, 0x11, 0xF2, 0xB1, 0xA9, 0xFC, 0x67, 0xB5, 0x61, 0x6E,
-0x22, 0xEE, 0x4E, 0x7C, 0x27, 0xC2, 0xEA, 0x2E, 0x00, 0xC8, 0xC7, 0xE4, 0xEE, 0x3D, 0xCE, 0xC6,
-0x26, 0xC4, 0x48, 0xE8, 0x7B, 0x2B, 0x5B, 0xAB, 0xBE, 0xF0, 0x39, 0xCD, 0xE4, 0x72, 0x9F, 0x15,
-0xE6, 0xA9, 0xDE, 0xC1, 0xA0, 0x3C, 0x0B, 0x40, 0xCB, 0x7D, 0x96, 0x86, 0x74, 0xDC, 0xDC, 0xB2,
-0xE4, 0xDF, 0x60, 0x8E, 0xA6, 0x11, 0x47, 0x03, 0x94, 0x92, 0x09, 0xFA, 0xF8, 0xF6, 0xF4, 0x57,
-0xD8, 0xA2, 0x9E, 0x93, 0xCF, 0x39, 0x11, 0xB2, 0x69, 0x19, 0x0F, 0x74, 0x2D, 0x96, 0x72, 0xD8,
-0xEA, 0xCE, 0x84, 0x04, 0x96, 0x7E, 0xA4, 0x4C, 0x82, 0x47, 0xE7, 0xA2, 0x4A, 0xDC, 0x35, 0x06,
-0x21, 0x6A, 0xAA, 0x27, 0xF5, 0x73, 0x17, 0xEA, 0x39, 0x34, 0x18, 0x0C, 0xD0, 0x73, 0xF4, 0xF4,
-0xA9, 0xE6, 0xA8, 0x58, 0x41, 0xAC, 0xA8, 0xB1, 0x9D, 0x76, 0xBB, 0x8A, 0xC3, 0x5C, 0x4F, 0x5F,
-0x9B, 0x70, 0x80, 0x25, 0x06, 0x99, 0x27, 0x17, 0xEF, 0x7E, 0x6F, 0x65, 0x98, 0x0B, 0x52, 0x70,
-0x17, 0x19, 0x4B, 0x05, 0xB9, 0x84, 0x46, 0xD2, 0x52, 0x7B, 0xFE, 0x13, 0x40, 0x4C, 0x26, 0xB0,
-0xEC, 0x5B, 0x63, 0x22, 0x0F, 0x63, 0xA2, 0x2E, 0x5F, 0xCF, 0x8E, 0x83, 0xA6, 0x43, 0x33, 0x67,
-0xAB, 0x75, 0x83, 0xE3, 0x5C, 0xD9, 0xB2, 0x14, 0xD2, 0xA2, 0x19, 0xFA, 0xFB, 0xEF, 0x52, 0x8E,
-0xB8, 0x95, 0x9D, 0xCF, 0x02, 0x52, 0xCD, 0x50, 0xCD, 0x3C, 0x88, 0x25, 0x0D, 0x6A, 0x34, 0x0C,
-0x1E, 0xC4, 0x8E, 0x93, 0x0C, 0xF6, 0xEB, 0xE0, 0x89, 0x53, 0x12, 0x68, 0x8F, 0x00, 0xF7, 0xF9,
-0xF2, 0x5A, 0xE3, 0xBF, 0x20, 0x8C, 0x89, 0x96, 0x14, 0xE2, 0x58, 0x90, 0x7B, 0x0A, 0x23, 0x9C,
-0x33, 0x7E, 0x40, 0xA4, 0xD9, 0x4F, 0xD7, 0x49, 0xD2, 0x54, 0xC1, 0x9C, 0xEA, 0xA1, 0xB2, 0x42,
-0x9A, 0x52, 0x11, 0x1D, 0xA7, 0x81, 0x52, 0x7A, 0x83, 0x34, 0x43, 0x47, 0x17, 0x74, 0x0F, 0x95,
-0x17, 0x90, 0x51, 0x0E, 0xAB, 0x74, 0x5C, 0x27, 0x67, 0x3E, 0xFF, 0x50, 0xFE, 0xC9, 0x67, 0x29,
-0x35, 0x8F, 0x3A, 0x01, 0x0B, 0x82, 0x87, 0x4A, 0x90, 0x39, 0x1F, 0xB1, 0x3A, 0xEE, 0x7A, 0xF2,
-0xA1, 0x9C, 0x47, 0xBA, 0xB9, 0x48, 0x89, 0x10, 0x26, 0x5D, 0x57, 0x47, 0xF0, 0x92, 0x4A, 0xC9,
-0x81, 0x34, 0x78, 0x3F, 0x29, 0x0D, 0x5B, 0xCA, 0x81, 0xE9, 0x0B, 0x1B, 0x5B, 0x2D, 0xB5, 0xA5,
-0xDC, 0x37, 0x85, 0x1E, 0x44, 0x36, 0x5E, 0x2F, 0x08, 0x7B, 0xA8, 0xB1, 0x8D, 0x9A, 0x9B, 0x74,
-0xD8, 0x82, 0x22, 0xD3, 0x78, 0xD2, 0xB8, 0xA7, 0x2A, 0x21, 0xE5, 0xC9, 0x04, 0x73, 0x72, 0x43,
-0xB8, 0x80, 0x98, 0x2A, 0xAB, 0x70, 0x54, 0x10, 0xA0, 0x0F, 0x86, 0xA2, 0xD7, 0xD8, 0x6E, 0xAE,
-0x05, 0xE5, 0xDA, 0xF3, 0x48, 0x29, 0xD3, 0x78, 0x9F, 0x5E, 0xA7, 0x6C, 0x92, 0xA2, 0x05, 0xD3,
-0xB2, 0x52, 0x5F, 0xD7, 0x46, 0xBE, 0x56, 0xE4, 0xEC, 0x8C, 0xA4, 0x4D, 0xE7, 0xCD, 0xE1, 0xA5,
-0xF3, 0x0C, 0x39, 0x1E, 0xA8, 0x6D, 0x6A, 0x01, 0xDC, 0x49, 0x9E, 0x93, 0x8A, 0x24, 0x2F, 0x48,
-0x1A, 0x34, 0x2B, 0x0B, 0xDA, 0x04, 0xD6, 0x0C, 0x9B, 0x40, 0x15, 0x88, 0x19, 0x0E, 0x36, 0x65,
-0xFE, 0x3B, 0x3B, 0x0C, 0x60, 0x82, 0xED, 0xD9, 0xE1, 0x0D, 0x10, 0x9C, 0x52, 0x01, 0x50, 0x11,
-0xDE, 0x6C, 0xE8, 0xBA, 0xD9, 0x78, 0xB6, 0x64, 0x4F, 0xAA, 0xEA, 0xC2, 0x37, 0x0F, 0x0A, 0xD2,
-0x92, 0x50, 0x75, 0x89, 0x2C, 0x02, 0xB5, 0x22, 0x08, 0xBE, 0x5A, 0x68, 0xAD, 0xD7, 0xD6, 0x15,
-0xC4, 0x96, 0x97, 0xE5, 0x82, 0x6C, 0xCE, 0x03, 0x8E, 0xA0, 0x8B, 0x28, 0xC1, 0x46, 0x14, 0x0E,
-0xAD, 0x8C, 0xEB, 0xCF, 0x03, 0x12, 0xE2, 0x3C, 0xD6, 0x65, 0xF8, 0x9F, 0xD5, 0x6C, 0xED, 0xFF,
-0xB3, 0x77, 0x17, 0x26, 0x00, 0x8C, 0xF8, 0x0B, 0x22, 0xF3, 0x6C, 0x53, 0x08, 0xC8, 0x82, 0xE3,
-0xAF, 0x50, 0xB7, 0xC1, 0x27, 0x4E, 0x01, 0x9B, 0x7B, 0x09, 0xDD, 0x8C, 0xE2, 0x83, 0x33, 0x53,
-0x1B, 0xC0, 0x22, 0x6F, 0xEA, 0x4E, 0x26, 0x13, 0x57, 0x9F, 0xC1, 0xE5, 0x3C, 0x26, 0xA9, 0x2A,
-0x74, 0x50, 0xB2, 0x2C, 0xBD, 0xBF, 0x61, 0xFF, 0x50, 0xD1, 0x3E, 0x2C, 0xBB, 0x87, 0xCA, 0x65,
-0x8B, 0x63, 0xC2, 0x65, 0xD3, 0x01, 0xB3, 0x25, 0x24, 0x64, 0x81, 0x04, 0xBE, 0x81, 0x74, 0x27,
-0x72, 0xDF, 0x07, 0xEF, 0x87, 0x79, 0x1C, 0xCF, 0x1E, 0x3B, 0x77, 0x59, 0x5C, 0x25, 0x4F, 0x28,
-0xAB, 0x8B, 0x9E, 0x44, 0xB9, 0xE3, 0xA8, 0xB8, 0x6D, 0x2E, 0xA2, 0x13, 0x50, 0xE4, 0xB3, 0x0B,
-0x28, 0xA1, 0xBE, 0x64, 0x80, 0xA3, 0xA2, 0x77, 0xB6, 0x2C, 0x51, 0x8A, 0x11, 0x34, 0x33, 0x38,
-0x81, 0x0A, 0xC8, 0xC1, 0x1A, 0xF4, 0xE7, 0x5F, 0xF6, 0xB1, 0x80, 0x61, 0xAB, 0x0E, 0x3A, 0x0F,
-0xB1, 0x1F, 0x35, 0x17, 0x98, 0xE9, 0x58, 0x7D, 0x86, 0xAE, 0xC9, 0xAC, 0x0A, 0xBD, 0x25, 0xD3,
-0x56, 0x96, 0x8B, 0xA8, 0x69, 0x7C, 0xF3, 0xFE, 0xFC, 0x78, 0x9F, 0x25, 0xD0, 0x30, 0x81, 0x7E,
-0x4D, 0xFD, 0xE4, 0x36, 0x72, 0x06, 0x0E, 0xFC, 0xAD, 0x98, 0xD7, 0x02, 0x6C, 0x85, 0xED, 0x85,
-0xA0, 0x0C, 0xD0, 0x27, 0xFB, 0x83, 0x55, 0x91, 0x57, 0xB0, 0x3B, 0x6D, 0x3A, 0x4F, 0x2B, 0x23,
-0x41, 0x27, 0x19, 0xF5, 0x88, 0x3D, 0xC9, 0x21, 0x32, 0x79, 0x6A, 0xD7, 0x9C, 0x45, 0xCB, 0x5B,
-0xB4, 0xB9, 0x7D, 0xCF, 0xBC, 0x73, 0x79, 0xD4, 0x57, 0x3C, 0x8A, 0x1E, 0x38, 0xA0, 0x37, 0xC8,
-0x8F, 0xB1, 0x10, 0x03, 0x67, 0x71, 0x34, 0xE2, 0x2C, 0x5B, 0xE2, 0xD5, 0xF9, 0xF5, 0xA3, 0xF5,
-0x15, 0x22, 0x4D, 0x48, 0x93, 0xF1, 0x2A, 0xA1, 0x83, 0x04, 0xF7, 0x97, 0xAF, 0x6F, 0x82, 0x5C,
-0xFA, 0x51, 0x00, 0x6B, 0x34, 0x66, 0x99, 0x7E, 0x75, 0x33, 0xC9, 0xE6, 0xAF, 0x02, 0xBC, 0x3C,
-0x53, 0xA9, 0x51, 0x78, 0x3B, 0xED, 0x9D, 0xAE, 0xD7, 0x7E, 0xE1, 0x1D, 0xC3, 0x84, 0x2B, 0x3E,
-0xE7, 0xEA, 0x2D, 0x4F, 0x06, 0x9D, 0x02, 0x04, 0xA2, 0x1C, 0x38, 0xA7, 0x8A, 0xA9, 0x25, 0x53,
-0x64, 0x38, 0x5D, 0xD3, 0x4E, 0x1F, 0x8A, 0x0E, 0x5F, 0x9F, 0x9E, 0x1E, 0x1E, 0xA8, 0xC5, 0xC7,
-0x59, 0x0C, 0x31, 0x0C, 0x08, 0x00, 0xDD, 0x8A, 0x4D, 0x1E, 0x18, 0x55, 0x6D, 0xE2, 0xFA, 0x99,
-0xB8, 0x2D, 0x2E, 0xEA, 0x00, 0x6B, 0x04, 0xBC, 0xD1, 0x92, 0x39, 0x5A, 0x2C, 0x8F, 0x33, 0x3C,
-0x26, 0x00, 0x71, 0xC7, 0x7E, 0xA8, 0x8B, 0x68, 0x30, 0x28, 0x95, 0xBA, 0xE1, 0xA2, 0xB4, 0x15,
-0x23, 0x3D, 0x74, 0x38, 0xCD, 0x28, 0xA7, 0x6A, 0x01, 0xE0, 0x18, 0x75, 0x76, 0x5A, 0xDD, 0x76,
-0x6B, 0xA7, 0x0B, 0x1C, 0xBB, 0x16, 0xC7, 0x6C, 0x58, 0x8A, 0xD9, 0xCB, 0x88, 0x0A, 0x88, 0x22,
-0x48, 0x0D, 0x38, 0x8E, 0xD9, 0x44, 0xA0, 0x19, 0xCB, 0x91, 0x64, 0xA8, 0xC8, 0x17, 0x32, 0x22,
-0xE8, 0xED, 0x1F, 0x97, 0x97, 0x68, 0xC4, 0xD9, 0x35, 0xE8, 0x4C, 0xD3, 0x90, 0x21, 0x9C, 0x06,
-0xF0, 0x7F, 0x86, 0xD4, 0x51, 0x9F, 0x5A, 0x16, 0x20, 0x54, 0x14, 0xB6, 0xB4, 0xD6, 0x05, 0x7A,
-0x96, 0xC4, 0xBE, 0x82, 0x09, 0x41, 0xC0, 0x46, 0x2C, 0x18, 0x98, 0x2C, 0x89, 0xB0, 0x5E, 0x5A,
-0x83, 0xF5, 0x5C, 0x89, 0x60, 0x7F, 0xA1, 0x6F, 0x61, 0x2F, 0x67, 0x42, 0x74, 0x35, 0x91, 0xBF,
-0x74, 0xCA, 0x86, 0xF4, 0xF5, 0xE1, 0xD8, 0xF0, 0xF8, 0xAC, 0xD7, 0xF7, 0xCC, 0x65, 0x99, 0xC4,
-0x9C, 0x2E, 0xAD, 0x9C, 0x82, 0x2B, 0x80, 0xD5, 0x96, 0x04, 0xA5, 0xB0, 0x8A, 0xCC, 0x95, 0xA4,
-0x32, 0x86, 0xCB, 0x43, 0x75, 0xD2, 0xA3, 0xCD, 0x3F, 0x3E, 0x53, 0x86, 0x72, 0xD5, 0xB1, 0xB0,
-0x50, 0xC1, 0xC3, 0x57, 0x11, 0x71, 0x90, 0x5E, 0xB2, 0x03, 0xC7, 0x19, 0xF6, 0x47, 0xBC, 0x56,
-0xAD, 0x57, 0x3A, 0xF5, 0x81, 0xF7, 0x03, 0x72, 0x6F, 0xFD, 0xF4, 0x1E, 0xA7, 0xD0, 0xD0, 0x5C,
-0x97, 0x74, 0xC4, 0x86, 0xBD, 0xDE, 0xF3, 0x00, 0xC4, 0x0F, 0xD5, 0xF2, 0x82, 0xA8, 0x17, 0x7D,
-0xE8, 0xF8, 0xE0, 0xFE, 0x18, 0x06, 0x0B, 0x0C, 0x83, 0x0A, 0xFD, 0xC4, 0x9C, 0xF1, 0x52, 0x3B,
-0x58, 0xD2, 0xD4, 0x27, 0xB7, 0x2A, 0xB6, 0xB2, 0xC4, 0xEC, 0x73, 0xD8, 0x8A, 0x20, 0xD0, 0x8F,
-0xAC, 0xAE, 0xED, 0xD5, 0x83, 0x53, 0x67, 0x78, 0x3E, 0xDF, 0x62, 0xE9, 0xA5, 0xA8, 0xEB, 0x5B,
-0xCF, 0x5E, 0xE3, 0x65, 0x58, 0x2C, 0x5E, 0xE6, 0xA4, 0xB2, 0x46, 0x78, 0x09, 0x22, 0xDD, 0xEB,
-0x8F, 0xD8, 0xD4, 0xC0, 0x54, 0xDE, 0x0C, 0x16, 0xA8, 0x95, 0x27, 0x36, 0xF0, 0x5F, 0x35, 0xB0,
-0xE8, 0xF7, 0x87, 0x1B, 0xCD, 0xA8, 0x75, 0xE6, 0x7A, 0x3E, 0xFB, 0xEF, 0x80, 0x7E, 0xA8, 0x76,
-0x9B, 0x68, 0xB1, 0x29, 0xFD, 0xBE, 0x80, 0x5B, 0x1B, 0xE2, 0x02, 0x6D, 0x6B, 0xF4, 0x87, 0x81,
-0xFA, 0x48, 0x6F, 0xB5, 0xD1, 0x72, 0x4F, 0xFE, 0x7D, 0xC1, 0x2E, 0x9D, 0x08, 0x14, 0x70, 0x97,
-0xC6, 0x7F, 0x18, 0xC0, 0xCF, 0xDF, 0xBC, 0x46, 0x6F, 0x4D, 0x4E, 0xFF, 0x8E, 0x38, 0x9B, 0x73,
-0x84, 0x02, 0x5C, 0x73, 0xF3, 0xC3, 0x20, 0x7A, 0x50, 0x9C, 0xE2, 0x7C, 0x5F, 0x44, 0x17, 0x67,
-0x4B, 0x05, 0xA8, 0x8B, 0xFB, 0x1F, 0x06, 0x57, 0xDD, 0x0C, 0x40, 0x27, 0xFC, 0xFD, 0xB1, 0x5D,
-0x9E, 0xAB, 0x15, 0xE0, 0x2E, 0x07, 0xFE, 0x97, 0xE8, 0x1A, 0x33, 0x55, 0x83, 0x5D, 0x77, 0x82,
-0x31, 0x5C, 0x3D, 0xB1, 0xD8, 0x6D, 0x3F, 0xB9, 0x53, 0x4F, 0xD4, 0xD0, 0xAF, 0x1E, 0x1A, 0x95,
-0x8C, 0x1B, 0x06, 0x80, 0x8A, 0xF1, 0x84, 0xA6, 0x83, 0x46, 0x1B, 0x3E, 0xF1, 0x74, 0xD0, 0xE8,
-0xB4, 0xE1, 0xCA, 0xB4, 0x45, 0xFA, 0x7A, 0x88, 0x74, 0x6B, 0xB4, 0xB9, 0x15, 0x2B, 0xBE, 0xF7,
-0x30, 0x6F, 0xA7, 0x2E, 0x60, 0xC7, 0x8D, 0xCC, 0x51, 0x49, 0xCE, 0xAB, 0x92, 0x6E, 0xDF, 0x53,
-0xAD, 0xB8, 0x35, 0xF6, 0xD8, 0x75, 0xFB, 0xC5, 0xD7, 0x02, 0x0C, 0x57, 0x73, 0xA3, 0xBA, 0x71,
-0x1F, 0xDA, 0x93, 0xEB, 0x81, 0x53, 0x9C, 0x49, 0xC5, 0xCC, 0x64, 0xF2, 0x96, 0xFE, 0xAA, 0x5D,
-0xC3, 0x33, 0x47, 0x33, 0x0D, 0xE8, 0xCB, 0xDF, 0xEB, 0x2B, 0xB4, 0xBA, 0x87, 0x32, 0x4C, 0x86,
-0xAE, 0x5B, 0xB9, 0x91, 0x2A, 0x2E, 0x81, 0x4C, 0x6F, 0x2D, 0xD5, 0x5E, 0x53, 0x7F, 0xCF, 0xEF,
-0x3F, 0xC7, 0x47, 0x1D, 0xEB, 0xFF, 0x27, 0x00, 0x00
+//File: setuppage.html.gz, Size: 4355
+#define setuppage_html_gz_len 4355
+const uint8_t setuppage_html_gz[] PROGMEM = {
+0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xED, 0x5D, 0x79, 0x73, 0xDB, 0x38,
+0xB2, 0xFF, 0x7F, 0xAB, 0xDE, 0x77, 0xC0, 0x68, 0x2A, 0xA1, 0x5C, 0x89, 0x0E, 0xDB, 0x71, 0x92,
+0x75, 0x2C, 0x55, 0xF9, 0x52, 0xC6, 0x59, 0x67, 0xE2, 0xB5, 0x94, 0x99, 0x79, 0xB3, 0xB5, 0xB5,
+0x05, 0x91, 0x90, 0x84, 0x98, 0x24, 0x38, 0x00, 0x69, 0xD9, 0x79, 0x9B, 0xEF, 0xFE, 0x1A, 0x20,
+0x78, 0x1F, 0xA2, 0x64, 0x67, 0x37, 0xDA, 0xAC, 0x9C, 0xC4, 0x24, 0xD8, 0xEC, 0xE3, 0xD7, 0x8D,
+0xC6, 0xC1, 0xA6, 0x72, 0xF4, 0xC3, 0xD9, 0x87, 0xD3, 0xC9, 0xFF, 0x5E, 0x9D, 0xA3, 0x85, 0xEF,
+0xD8, 0xC3, 0xFF, 0xF9, 0xD3, 0x91, 0xFE, 0x2D, 0x8F, 0x08, 0xB6, 0xE0, 0x08, 0xC1, 0xE7, 0xC8,
+0xA6, 0xEE, 0x0D, 0xE2, 0xC4, 0x1E, 0x18, 0xC2, 0xBF, 0xB7, 0x89, 0x58, 0x10, 0xE2, 0x1B, 0x68,
+0xC1, 0xC9, 0x6C, 0x60, 0x2C, 0x7C, 0xDF, 0x13, 0x87, 0xBD, 0x9E, 0x69, 0xB9, 0x9F, 0x44, 0xD7,
+0xB4, 0x59, 0x60, 0xCD, 0x6C, 0xCC, 0x49, 0xD7, 0x64, 0x4E, 0x0F, 0x7F, 0xC2, 0x77, 0x3D, 0x9B,
+0x4E, 0x45, 0x6F, 0xC6, 0x5C, 0xBF, 0x83, 0x97, 0x44, 0x30, 0x87, 0xF4, 0x0E, 0xBA, 0xBB, 0x07,
+0xDD, 0xFD, 0x9E, 0x29, 0x44, 0x0F, 0xDB, 0x76, 0xD7, 0xA1, 0x6E, 0x17, 0x8E, 0x0D, 0x44, 0x5D,
+0x9F, 0xCC, 0x39, 0xF5, 0xEF, 0x41, 0xD0, 0x02, 0x1F, 0xEC, 0xEE, 0x75, 0xE8, 0x9D, 0xFD, 0xE1,
+0xF7, 0x77, 0x77, 0xF6, 0x6B, 0xFC, 0x69, 0xF7, 0xF4, 0x73, 0xDF, 0xF9, 0xCB, 0xA7, 0xFB, 0xD1,
+0xE4, 0xDD, 0x5F, 0xEF, 0x7A, 0xE2, 0xD9, 0xC7, 0x97, 0x4B, 0xD6, 0x67, 0x2F, 0xAF, 0x9E, 0x9D,
+0xFE, 0x7E, 0x75, 0xFD, 0xEE, 0xB7, 0x67, 0xF3, 0xCF, 0x64, 0xFF, 0xDD, 0xE2, 0xF5, 0x88, 0xB3,
+0x9E, 0x33, 0xB9, 0xBF, 0xE4, 0x07, 0xBC, 0xF7, 0xCB, 0xDD, 0xB3, 0xE0, 0x97, 0x57, 0xEF, 0x5E,
+0x5F, 0xDF, 0x5E, 0xCF, 0x7E, 0xF7, 0x0E, 0x9E, 0xFD, 0xF6, 0xE7, 0x19, 0xBD, 0x7D, 0xFB, 0xEA,
+0x78, 0x30, 0x30, 0x90, 0xC9, 0x99, 0x10, 0x8C, 0xD3, 0x39, 0x75, 0x07, 0x06, 0x76, 0x99, 0x7B,
+0xEF, 0xB0, 0x00, 0x74, 0x00, 0xA3, 0x08, 0xE7, 0x84, 0x7B, 0xCC, 0xA6, 0x26, 0x28, 0xE2, 0xB2,
+0x4E, 0xD4, 0x64, 0xA0, 0x5E, 0x84, 0x88, 0xC2, 0x41, 0x9F, 0xC8, 0xCF, 0x94, 0x59, 0xF7, 0xE8,
+0xFF, 0x92, 0x73, 0xD5, 0x86, 0xCD, 0x9B, 0x39, 0x67, 0x81, 0x6B, 0x75, 0x4C, 0x66, 0x33, 0x7E,
+0x88, 0x7E, 0x9C, 0xED, 0xCA, 0x9F, 0x37, 0x59, 0x3A, 0x05, 0xCD, 0x0C, 0x3B, 0xD4, 0xBE, 0x3F,
+0x44, 0xC7, 0x9C, 0x62, 0xFB, 0x39, 0x12, 0xD8, 0x15, 0x1D, 0x41, 0x38, 0x9D, 0xA5, 0x88, 0xBF,
+0x24, 0x87, 0x80, 0xAE, 0xEB, 0x63, 0xEA, 0x12, 0x9E, 0x97, 0x6A, 0x51, 0xE1, 0xD9, 0x18, 0x38,
+0xCD, 0x6C, 0x72, 0x97, 0x97, 0x04, 0x4D, 0x1D, 0x8B, 0x72, 0x62, 0xFA, 0x94, 0xB9, 0x87, 0x08,
+0xD4, 0x0A, 0x1C, 0x37, 0x47, 0xF4, 0x29, 0x10, 0x3E, 0x9D, 0xDD, 0x77, 0xA4, 0x04, 0xE2, 0xFA,
+0x40, 0x05, 0xFF, 0x12, 0x9E, 0xA3, 0xC2, 0x36, 0x9D, 0xBB, 0x1D, 0xEA, 0x13, 0x47, 0x54, 0x50,
+0x2C, 0x08, 0x9D, 0x2F, 0xE4, 0xED, 0xD8, 0x36, 0xDB, 0xBB, 0xFD, 0xFE, 0x13, 0xD4, 0x41, 0xF0,
+0xCB, 0xBB, 0xDB, 0xA9, 0x30, 0xC9, 0x66, 0x73, 0xD6, 0xD9, 0xC8, 0xAE, 0x7A, 0x65, 0xF2, 0x32,
+0xF2, 0x9C, 0x97, 0xD4, 0xF2, 0x17, 0x87, 0xA1, 0x6E, 0x15, 0x36, 0x94, 0x5D, 0x73, 0x30, 0x87,
+0xD8, 0xE9, 0xF0, 0x90, 0x62, 0x2F, 0x4B, 0x50, 0xB0, 0xCB, 0x27, 0x77, 0x7E, 0x5E, 0xB0, 0x72,
+0xBC, 0xA0, 0x9F, 0xC9, 0x21, 0xDA, 0x7F, 0x59, 0xE0, 0xAF, 0xAE, 0x2E, 0xB5, 0x02, 0x53, 0x66,
+0x5B, 0x15, 0xEC, 0x67, 0x8C, 0x3B, 0xD5, 0xB0, 0x15, 0x83, 0x70, 0xB9, 0x00, 0xA0, 0x72, 0xB2,
+0x3C, 0x6C, 0x59, 0xD4, 0x9D, 0x17, 0xCC, 0x50, 0x1C, 0x18, 0xB7, 0x08, 0xEF, 0x70, 0x6C, 0xD1,
+0x40, 0x48, 0x28, 0x4A, 0x28, 0xEE, 0x3A, 0xD0, 0x5F, 0x2D, 0xB6, 0x3C, 0x44, 0x7D, 0xF8, 0x91,
+0x24, 0x88, 0xCF, 0xA7, 0xB8, 0xDD, 0x7F, 0x8E, 0xF4, 0x9F, 0xEE, 0xFE, 0xCE, 0x9B, 0x52, 0xD8,
+0x5F, 0xF7, 0x9F, 0x94, 0x03, 0xEB, 0x33, 0xAF, 0x0E, 0x56, 0x1B, 0x4F, 0x89, 0x5D, 0x19, 0x24,
+0x53, 0x9B, 0x99, 0x37, 0xE5, 0x02, 0x65, 0x28, 0x96, 0x4B, 0x9C, 0x32, 0xDF, 0x67, 0xCE, 0x21,
+0x3A, 0x58, 0xCB, 0x17, 0xF1, 0xF5, 0xD0, 0x93, 0xBB, 0x45, 0x4F, 0x46, 0xBD, 0x7F, 0x7F, 0x7F,
+0xBF, 0xDC, 0x16, 0xEA, 0x7A, 0x81, 0xFF, 0x37, 0xFF, 0xDE, 0x23, 0x03, 0x43, 0x06, 0x8A, 0xF1,
+0xF7, 0xEA, 0x18, 0xCD, 0xEB, 0x1E, 0xBB, 0xAE, 0xD4, 0x31, 0x19, 0xD7, 0x15, 0xED, 0x0A, 0x09,
+0xE0, 0x5E, 0x70, 0x98, 0x80, 0x84, 0x67, 0xA1, 0x1F, 0x4D, 0xD3, 0xAC, 0x47, 0xA7, 0x24, 0x44,
+0xAA, 0xCD, 0xAF, 0x30, 0x52, 0x04, 0x53, 0x87, 0x96, 0x98, 0x59, 0x92, 0x32, 0x5F, 0x9C, 0x1E,
+0x8F, 0x0E, 0xFA, 0xE5, 0x88, 0xD6, 0x86, 0xF2, 0x43, 0xF0, 0x80, 0xE1, 0x20, 0xCF, 0xD7, 0x0C,
+0xB8, 0x90, 0x32, 0x3D, 0x46, 0x4B, 0x92, 0x5D, 0x4D, 0xCC, 0xD6, 0x03, 0x14, 0x5F, 0x5D, 0xDD,
+0xD3, 0xA7, 0x01, 0x38, 0xC0, 0xFD, 0x2F, 0x64, 0x6B, 0x40, 0xD6, 0xF5, 0xD9, 0x7C, 0x6E, 0x93,
+0xAF, 0x31, 0xAA, 0xA4, 0x4C, 0x88, 0x7A, 0xC6, 0x6E, 0xF5, 0x18, 0xA0, 0xF5, 0x28, 0x4D, 0x5A,
+0xD9, 0x81, 0x64, 0x35, 0x13, 0xB1, 0xA4, 0xBE, 0xB9, 0xC8, 0x73, 0xF1, 0x98, 0xA0, 0xE1, 0xA8,
+0x0E, 0x13, 0x35, 0xEC, 0xD3, 0xDB, 0xBC, 0x37, 0x62, 0x53, 0xA9, 0x0B, 0xF3, 0x39, 0xD2, 0xA9,
+0x49, 0x91, 0x2F, 0xAB, 0x47, 0xC2, 0xFD, 0x17, 0x0D, 0xD5, 0x53, 0xDD, 0x3D, 0xAF, 0x24, 0xF3,
+0xB0, 0x09, 0xD3, 0x3B, 0x18, 0x26, 0xCA, 0x05, 0xE7, 0x9B, 0x23, 0xA9, 0xFD, 0x0A, 0x91, 0x02,
+0x52, 0x56, 0xD1, 0xA9, 0x09, 0x14, 0x78, 0x0A, 0x59, 0x2D, 0x28, 0x04, 0x7C, 0x7D, 0x60, 0xAA,
+0x88, 0xCC, 0x6B, 0x62, 0x93, 0x99, 0x5F, 0x6C, 0xE5, 0x45, 0xF5, 0xE4, 0x27, 0x0A, 0x88, 0x42,
+0x7B, 0xB1, 0xAF, 0x16, 0xD3, 0x2D, 0x84, 0xF5, 0xF4, 0x86, 0xFA, 0x1D, 0x9F, 0xC3, 0x1C, 0x50,
+0xDB, 0xD1, 0x7D, 0x21, 0xF2, 0x4A, 0xD6, 0x5E, 0xCD, 0xF5, 0xDA, 0x1A, 0xA7, 0x85, 0x08, 0x1E,
+0x4E, 0x09, 0x4C, 0x23, 0xC8, 0xFA, 0x40, 0x46, 0x73, 0x44, 0xC3, 0xA8, 0xF0, 0xDC, 0x5E, 0xB1,
+0xEF, 0x6A, 0x5F, 0x97, 0x5C, 0x09, 0x41, 0x7E, 0x51, 0x92, 0x63, 0x42, 0x3C, 0x4B, 0xAE, 0x34,
+0x9A, 0xDE, 0x7C, 0x05, 0x48, 0x0F, 0x32, 0x03, 0x71, 0x7E, 0x98, 0x3B, 0x34, 0x17, 0xC4, 0xBC,
+0x21, 0x16, 0x7A, 0x56, 0x15, 0xA3, 0x25, 0xA1, 0xB0, 0xB7, 0xFB, 0xE7, 0x97, 0xA3, 0xBA, 0x19,
+0xC2, 0xE1, 0x8C, 0x99, 0x81, 0xA8, 0xE1, 0x99, 0x9F, 0x87, 0xC1, 0xA8, 0xDE, 0x80, 0x6B, 0x41,
+0xD7, 0x8A, 0x68, 0xC8, 0xA0, 0x28, 0x67, 0x9D, 0x87, 0x21, 0x64, 0x90, 0x6D, 0xC8, 0x6F, 0x6D,
+0xE9, 0xCE, 0xFC, 0x14, 0xAF, 0xE3, 0x88, 0x35, 0xA8, 0x9B, 0x51, 0x56, 0xCC, 0x28, 0xE0, 0x86,
+0x39, 0x59, 0x67, 0xDE, 0x54, 0x3F, 0xAB, 0xD1, 0x52, 0x8E, 0x7A, 0xE9, 0x85, 0xDE, 0x91, 0x30,
+0x39, 0xF5, 0xFC, 0xD4, 0xB2, 0x6F, 0x16, 0xB8, 0x6A, 0x29, 0x85, 0x02, 0xCF, 0x02, 0x6D, 0x2F,
+0x2C, 0x9B, 0xB4, 0x77, 0xF2, 0x3A, 0xDC, 0x62, 0x8E, 0xEE, 0xD0, 0x00, 0x59, 0xE0, 0x3D, 0x07,
+0x7A, 0x4B, 0x77, 0x4E, 0xFC, 0x73, 0x9B, 0xC8, 0xC3, 0x93, 0xFB, 0x0B, 0xAB, 0xDD, 0xA2, 0x2E,
+0x06, 0x2E, 0xB7, 0x90, 0x18, 0xDF, 0x53, 0x57, 0xB4, 0xF2, 0xB8, 0xD0, 0x19, 0x6A, 0x57, 0xDD,
+0x6B, 0x24, 0xF7, 0x9E, 0xBB, 0x78, 0x6A, 0x13, 0xCB, 0xD8, 0xE9, 0x6A, 0x87, 0x16, 0x14, 0x91,
+0x9F, 0xBB, 0xAE, 0xB2, 0xA8, 0xAB, 0x47, 0x03, 0x50, 0xCB, 0x50, 0x03, 0x41, 0xBE, 0xFF, 0x7E,
+0x41, 0xC4, 0x16, 0x85, 0x10, 0xA8, 0xE0, 0x20, 0xC7, 0xFE, 0x22, 0x83, 0xD4, 0xA7, 0xD4, 0x7D,
+0x31, 0x78, 0x62, 0xC1, 0x96, 0x13, 0x22, 0xFC, 0x0F, 0x9E, 0x3C, 0x15, 0x1B, 0x20, 0x78, 0x79,
+0x7E, 0x26, 0x19, 0x8C, 0x89, 0xEF, 0xC3, 0x44, 0x66, 0x4D, 0x08, 0x39, 0xF1, 0x60, 0xA9, 0x0F,
+0xEE, 0xBB, 0x24, 0xD6, 0xD8, 0x87, 0xDF, 0xEB, 0x43, 0x58, 0x06, 0x80, 0xFC, 0x54, 0xCA, 0xB4,
+0xC8, 0x34, 0x98, 0x2F, 0xE9, 0x8C, 0x26, 0xB2, 0x80, 0xCF, 0x0C, 0x03, 0xE6, 0x0F, 0x71, 0x44,
+0xB9, 0x2B, 0x57, 0xA3, 0x7F, 0x6C, 0xDD, 0x62, 0xD7, 0x24, 0xD6, 0x06, 0xD0, 0x47, 0xB7, 0x9E,
+0xD1, 0xDB, 0xF5, 0x60, 0xC7, 0xFA, 0xC6, 0xC8, 0x69, 0xDF, 0x64, 0xE0, 0xD6, 0x7E, 0xEA, 0x71,
+0x0D, 0x53, 0xC2, 0x29, 0x73, 0x67, 0x74, 0x5E, 0x81, 0xEB, 0x82, 0x83, 0x12, 0x2E, 0x59, 0xA2,
+0xDF, 0xDE, 0x5F, 0xFE, 0xE4, 0xFB, 0xDE, 0x35, 0xF9, 0x23, 0x80, 0x30, 0x6E, 0xE7, 0x71, 0x04,
+0xC2, 0x2E, 0x73, 0x39, 0xC1, 0xD6, 0xBD, 0x90, 0x01, 0x6A, 0x2E, 0x64, 0xB6, 0x93, 0x01, 0xA3,
+0x85, 0x15, 0xF9, 0xCB, 0x8F, 0x84, 0x5F, 0xDE, 0xAA, 0x6E, 0x54, 0x91, 0x8D, 0x06, 0x83, 0x01,
+0x7A, 0x81, 0x9E, 0x3E, 0x55, 0x2C, 0x25, 0x2F, 0x18, 0x4F, 0x64, 0xDB, 0x5E, 0xBF, 0x5F, 0xCA,
+0x22, 0x52, 0xD5, 0x54, 0x66, 0x9C, 0x61, 0x1F, 0x83, 0xD4, 0x77, 0xE3, 0x0F, 0x3F, 0x77, 0x3D,
+0xCC, 0x05, 0xD1, 0xEC, 0x85, 0x07, 0xDD, 0x96, 0x4C, 0x60, 0xE5, 0x9A, 0xD7, 0x3C, 0xFA, 0x54,
+0xE7, 0x2F, 0x0F, 0xFC, 0x7E, 0x8B, 0xED, 0x40, 0x9A, 0x93, 0x48, 0xE9, 0x52, 0x0F, 0xFD, 0xF3,
+0x9F, 0xC5, 0x69, 0xC5, 0x4A, 0x7E, 0x26, 0xB3, 0x48, 0x39, 0x47, 0x79, 0x65, 0x33, 0x9E, 0xD4,
+0xAA, 0xD0, 0xD1, 0xDA, 0x8C, 0x5F, 0x4D, 0xC2, 0xC9, 0x0A, 0x88, 0x09, 0x21, 0xAF, 0x4B, 0x51,
+0x65, 0xF9, 0x61, 0xA5, 0x34, 0xC2, 0x39, 0xE3, 0x67, 0xC4, 0x0F, 0x37, 0xFD, 0xAA, 0x44, 0x29,
+0x2A, 0x2B, 0xA2, 0xDA, 0x58, 0xD8, 0x8C, 0xBA, 0x54, 0x2C, 0x2E, 0x5C, 0x4B, 0xAA, 0x5D, 0x23,
+0x2E, 0xA4, 0xA3, 0x31, 0xDD, 0xC6, 0x02, 0x55, 0x22, 0x85, 0xF4, 0x51, 0x25, 0x28, 0xBA, 0xFE,
+0x60, 0x01, 0x61, 0x9F, 0x5B, 0x25, 0x46, 0xF7, 0xCC, 0x4D, 0x85, 0x39, 0x7F, 0xF8, 0xBE, 0x62,
+0x55, 0x25, 0x27, 0x26, 0xD8, 0x58, 0x04, 0xCC, 0xF0, 0x30, 0xBF, 0x94, 0x93, 0x73, 0xF1, 0x61,
+0x36, 0xAB, 0x92, 0x93, 0xA5, 0xDA, 0x58, 0x58, 0xCD, 0xEC, 0x24, 0xD7, 0x95, 0xF2, 0x84, 0x8F,
+0x20, 0x52, 0x4E, 0xA6, 0x2A, 0x3A, 0x6E, 0x86, 0x46, 0x75, 0xE2, 0xFD, 0xFE, 0xDA, 0xDD, 0xD8,
+0xC1, 0xB0, 0x7A, 0x7C, 0x1F, 0xE6, 0x9B, 0x72, 0x67, 0x45, 0x04, 0x9B, 0x07, 0x1F, 0x15, 0x26,
+0xAB, 0x13, 0x11, 0x13, 0x6C, 0x2C, 0xC2, 0x87, 0x01, 0xE7, 0xFA, 0xED, 0x49, 0x39, 0x50, 0xFA,
+0xE2, 0x86, 0xA9, 0x78, 0xF9, 0x8F, 0x70, 0x3D, 0x51, 0xCD, 0x1B, 0x96, 0x3E, 0x96, 0x5A, 0xB0,
+0x49, 0x09, 0x30, 0x49, 0x5F, 0x57, 0xC4, 0x72, 0xB5, 0x88, 0x25, 0xE6, 0xCE, 0x43, 0x44, 0x94,
+0xCF, 0xD4, 0xF2, 0x5D, 0x5F, 0x12, 0x6C, 0xEC, 0x02, 0xEC, 0xBD, 0x3F, 0x3E, 0x2D, 0xB7, 0x40,
+0x5D, 0xDA, 0x0C, 0xFE, 0xA9, 0xDA, 0x9C, 0x70, 0x89, 0x10, 0x75, 0x10, 0x25, 0x54, 0x9B, 0xE1,
+0xD3, 0xCA, 0x8B, 0x39, 0x0B, 0x67, 0x57, 0xAD, 0x9D, 0xAE, 0xDC, 0xC9, 0x3E, 0x0D, 0x37, 0x08,
+0x40, 0x66, 0xEB, 0x24, 0x26, 0x3C, 0x44, 0xAD, 0x67, 0xA8, 0x5D, 0xA7, 0xC4, 0x0E, 0x2C, 0x46,
+0x5B, 0x4F, 0x5A, 0xEB, 0xEA, 0x32, 0xA3, 0xE0, 0x6B, 0xCC, 0xC9, 0x2D, 0xE1, 0x02, 0x06, 0x95,
+0xA2, 0x0E, 0x23, 0x4D, 0x80, 0x7E, 0x09, 0x29, 0x0E, 0x5B, 0xCF, 0xDA, 0x99, 0x51, 0x29, 0x73,
+0x3F, 0x92, 0xDA, 0xB4, 0x3E, 0xBA, 0x37, 0x2E, 0x5B, 0xBA, 0x28, 0x66, 0xBA, 0x76, 0x90, 0x42,
+0x6C, 0x54, 0xF6, 0x30, 0x7D, 0x71, 0x33, 0x17, 0x87, 0xA3, 0x68, 0x25, 0xEF, 0xF8, 0xF2, 0x66,
+0xDC, 0x3D, 0x1C, 0x08, 0x52, 0xC9, 0x3C, 0xBA, 0xBA, 0xA9, 0xE6, 0x5C, 0xF8, 0x10, 0x26, 0x84,
+0xD7, 0x68, 0x9F, 0x22, 0xD9, 0x4C, 0x8A, 0xCB, 0x3E, 0x7F, 0xB6, 0x89, 0x69, 0xB3, 0x79, 0xA5,
+0x94, 0x0C, 0xC9, 0x66, 0x52, 0x16, 0x8E, 0x18, 0x13, 0x4E, 0x59, 0x20, 0x2A, 0xA5, 0x64, 0x48,
+0x36, 0x96, 0x32, 0x02, 0x56, 0x76, 0x9D, 0x8C, 0x88, 0x60, 0x53, 0x9F, 0xD8, 0x58, 0x9E, 0x5D,
+0x07, 0x2E, 0x0B, 0xAA, 0xC7, 0x84, 0x02, 0xD9, 0x86, 0xD2, 0x38, 0x74, 0xCB, 0x53, 0x76, 0x5B,
+0x17, 0x01, 0x69, 0x92, 0x87, 0x44, 0xC0, 0x84, 0x38, 0xDE, 0x8A, 0x08, 0xD0, 0x24, 0x1B, 0xA6,
+0x5A, 0x62, 0xD5, 0x8A, 0x48, 0xAE, 0xD7, 0xF2, 0x2F, 0xEC, 0x83, 0x54, 0xD0, 0xA5, 0x37, 0x9B,
+0x4A, 0x48, 0xBE, 0x64, 0x9B, 0xBE, 0x94, 0x2D, 0x26, 0x3D, 0xE2, 0xB6, 0x8D, 0xB7, 0xE7, 0x13,
+0xE3, 0x39, 0x32, 0x7A, 0x60, 0x4E, 0xB8, 0x4C, 0x85, 0x33, 0x9F, 0x07, 0xA4, 0x6C, 0xF9, 0x29,
+0x88, 0x6B, 0xB5, 0x2B, 0xF6, 0xE1, 0x96, 0x30, 0x8F, 0x67, 0x4B, 0x58, 0xA1, 0xDA, 0x0C, 0x5B,
+0xB5, 0xAB, 0xD2, 0xC6, 0xA3, 0x08, 0xA4, 0x6E, 0x6C, 0x59, 0xE7, 0xB7, 0x40, 0x70, 0x49, 0x05,
+0xA4, 0x6F, 0xC2, 0xE5, 0x3E, 0x99, 0x17, 0xF8, 0xAD, 0xE7, 0x09, 0x7F, 0x52, 0xBA, 0x66, 0x7D,
+0xF4, 0xA1, 0x8A, 0x74, 0x7D, 0xCC, 0x81, 0x99, 0x76, 0x6D, 0xD9, 0xD0, 0xF4, 0x25, 0x8F, 0x59,
+0x76, 0xF5, 0x9F, 0xBB, 0xB8, 0xCA, 0xD1, 0x15, 0x0E, 0x96, 0x9E, 0x94, 0x3F, 0xD1, 0x79, 0xD9,
+0x66, 0x8E, 0x7A, 0xB0, 0x3A, 0x62, 0xDC, 0x29, 0x82, 0x4F, 0x24, 0x9A, 0x5D, 0x8F, 0xAB, 0xDF,
+0x67, 0x64, 0x86, 0x03, 0x3B, 0xDC, 0x6A, 0x78, 0xE8, 0xCE, 0x84, 0x0A, 0xA6, 0xAB, 0x0F, 0xE3,
+0x30, 0x9A, 0x42, 0x15, 0xC6, 0xC4, 0x0F, 0xBC, 0xDA, 0x78, 0xF2, 0x35, 0xCF, 0x9F, 0x08, 0x06,
+0x5F, 0xB4, 0x0D, 0x8D, 0x7F, 0x67, 0x72, 0xEF, 0x11, 0xC9, 0x08, 0x7B, 0xE1, 0xE2, 0x17, 0xCC,
+0xEA, 0xDD, 0x75, 0x96, 0xCB, 0x65, 0x47, 0x55, 0x3A, 0x04, 0xDC, 0x26, 0xAE, 0x5C, 0xCB, 0xC3,
+0x5A, 0xA2, 0xA0, 0xFB, 0x63, 0x6E, 0x94, 0x94, 0xEC, 0x93, 0xA4, 0xB6, 0x49, 0xCA, 0x7B, 0x26,
+0xB6, 0x09, 0xF7, 0xDB, 0x46, 0xB4, 0xA5, 0x85, 0x04, 0xBE, 0x85, 0xE9, 0xA2, 0x08, 0x4C, 0x13,
+0x62, 0x69, 0x16, 0xD8, 0xF6, 0xFD, 0x0F, 0x46, 0xC3, 0x2E, 0x5B, 0x74, 0x8A, 0x34, 0x5F, 0xEF,
+0xC0, 0x48, 0xCF, 0x8C, 0xF4, 0x69, 0xB2, 0xC3, 0x06, 0x70, 0xF2, 0xFB, 0x31, 0x81, 0xE1, 0xCC,
+0x67, 0x00, 0xA8, 0xA4, 0x37, 0x76, 0xF2, 0xE2, 0x24, 0x27, 0x0F, 0x73, 0x48, 0xE1, 0x3E, 0x4C,
+0x68, 0x80, 0xD7, 0xDF, 0xFE, 0x9E, 0xA3, 0x88, 0xE4, 0xC8, 0xCA, 0x92, 0x73, 0x6C, 0x2E, 0xDA,
+0x31, 0x78, 0x2A, 0xFE, 0x9F, 0xA3, 0x1B, 0x72, 0x5F, 0x0A, 0x63, 0xC2, 0xB6, 0xEB, 0x05, 0x62,
+0xD1, 0x0E, 0xFD, 0xF4, 0xF1, 0xFA, 0xE2, 0x94, 0x39, 0x1E, 0x73, 0x41, 0xC5, 0xB6, 0xBA, 0xF5,
+0x19, 0x32, 0x06, 0x06, 0xFC, 0x5B, 0x72, 0x5D, 0x49, 0x28, 0xE8, 0x5C, 0xE8, 0x5D, 0xD2, 0x08,
+0x55, 0x72, 0x35, 0x48, 0x0B, 0xFD, 0xC4, 0x28, 0x04, 0xE2, 0xD3, 0x8A, 0xB8, 0x50, 0x19, 0x4C,
+0xDE, 0x54, 0xBC, 0xCC, 0x21, 0x58, 0xB9, 0x5B, 0x98, 0xBC, 0x27, 0x0F, 0x01, 0xA2, 0x7D, 0xFF,
+0xA3, 0x9E, 0x2E, 0x8B, 0x83, 0x43, 0xC9, 0x2A, 0x7A, 0x30, 0x60, 0xD1, 0x5B, 0x64, 0xDA, 0x58,
+0x88, 0x81, 0x11, 0x3F, 0x6A, 0x36, 0x52, 0xCF, 0x09, 0xD2, 0x04, 0xD9, 0x32, 0xA7, 0x34, 0x95,
+0xA2, 0xA4, 0xCE, 0x3C, 0x4D, 0x69, 0x20, 0xC1, 0xCD, 0xA4, 0xCA, 0x8E, 0xE3, 0x65, 0x77, 0x4E,
+0xFD, 0x45, 0x30, 0x85, 0xD9, 0x17, 0xD7, 0x8F, 0xDF, 0x54, 0xA9, 0xDD, 0x59, 0xE0, 0x9B, 0x8B,
+0x33, 0xE8, 0xDB, 0x36, 0xF3, 0x7A, 0x27, 0x97, 0x97, 0xE7, 0x67, 0xB2, 0x43, 0x71, 0x66, 0x43,
+0x48, 0xF6, 0xE4, 0x4A, 0xB4, 0x07, 0x8C, 0x7A, 0xD0, 0x8D, 0x7A, 0x17, 0x70, 0xDB, 0x93, 0xBD,
+0xBE, 0xF8, 0x23, 0x90, 0x65, 0x7A, 0x9E, 0x3B, 0x37, 0x20, 0x6E, 0xFD, 0x81, 0x71, 0x29, 0xC5,
+0xE5, 0xD5, 0x11, 0x1E, 0x76, 0x33, 0x9A, 0xAB, 0xFA, 0x94, 0x61, 0x4E, 0x00, 0x40, 0x04, 0x74,
+0x69, 0x83, 0x7B, 0x60, 0x71, 0x05, 0x00, 0xD9, 0x82, 0xA5, 0x82, 0xC4, 0xC5, 0x2E, 0x70, 0x47,
+0xC0, 0x1E, 0x25, 0xFC, 0x51, 0xDC, 0xA3, 0xAE, 0xF0, 0x9C, 0x80, 0x17, 0x76, 0x0B, 0x77, 0xED,
+0x21, 0x6A, 0x0D, 0x0A, 0x2B, 0x80, 0x61, 0x3C, 0xE3, 0xD7, 0x2D, 0x87, 0xE8, 0xFC, 0xCE, 0xA3,
+0x9C, 0xCA, 0x0E, 0x83, 0x6D, 0x24, 0xEB, 0x10, 0xBB, 0x7B, 0x2F, 0x80, 0xE3, 0x7E, 0x9E, 0xA3,
+0x37, 0x9C, 0x2C, 0xA8, 0x80, 0xF8, 0x82, 0x04, 0x82, 0x6D, 0x9B, 0x2D, 0x05, 0xBA, 0x67, 0x01,
+0xF2, 0x19, 0xD2, 0x59, 0xC5, 0x5F, 0x10, 0xF4, 0xFE, 0xAF, 0x93, 0x09, 0x9A, 0x72, 0x76, 0x03,
+0x3A, 0x52, 0x77, 0xC6, 0x10, 0x76, 0x2D, 0xF8, 0x7B, 0x8F, 0x64, 0x49, 0x85, 0xEC, 0x33, 0x20,
+0x43, 0x68, 0xDD, 0xBB, 0x47, 0x3D, 0x2F, 0x2F, 0x44, 0x62, 0x81, 0x20, 0x7C, 0x17, 0xCC, 0x1A,
+0x84, 0x29, 0x14, 0x61, 0xD5, 0xD7, 0x06, 0xD9, 0x44, 0x8A, 0x60, 0x98, 0x50, 0xA7, 0x03, 0x43,
+0x07, 0x6B, 0x3A, 0xD3, 0xBF, 0xC9, 0x83, 0xA8, 0x78, 0x87, 0xC5, 0x06, 0x20, 0x61, 0x20, 0x77,
+0x59, 0x87, 0x17, 0x57, 0x87, 0x47, 0x3D, 0xD5, 0x56, 0x46, 0x1C, 0x3E, 0xAE, 0x4F, 0x95, 0x20,
+0x49, 0x38, 0xE5, 0x7D, 0xC8, 0x85, 0xEE, 0x15, 0x1E, 0xF9, 0xD4, 0xB7, 0xE1, 0xF0, 0x5C, 0x3E,
+0x33, 0x57, 0xD6, 0x5F, 0x5C, 0x49, 0x3B, 0xB9, 0x5C, 0xB7, 0xB1, 0x99, 0x44, 0x87, 0xA7, 0x01,
+0x31, 0x90, 0xEA, 0xCD, 0x03, 0xC3, 0x18, 0x1E, 0x4D, 0xF9, 0x0A, 0x0D, 0xD5, 0xBE, 0xED, 0xF0,
+0x58, 0x25, 0x4A, 0x70, 0xBC, 0x45, 0xD6, 0x57, 0x56, 0xB1, 0xD0, 0xEA, 0x86, 0xC7, 0x05, 0x85,
+0x71, 0xC8, 0x5F, 0x6D, 0x05, 0x83, 0xD8, 0x87, 0xA9, 0x4C, 0x2D, 0x63, 0x28, 0x67, 0xF5, 0xE0,
+0xE2, 0x8B, 0xB3, 0x0D, 0xB0, 0xB5, 0x62, 0x6C, 0xAD, 0x12, 0x55, 0x45, 0xC4, 0x39, 0x51, 0xD4,
+0x22, 0xB7, 0xD4, 0x24, 0x6B, 0xE9, 0x18, 0x6E, 0x2D, 0x0C, 0x7F, 0x95, 0xDB, 0x13, 0x1A, 0xDC,
+0x2B, 0x59, 0xF4, 0x80, 0xE4, 0xB6, 0xC2, 0x71, 0xE8, 0xBB, 0x3A, 0xD5, 0x7D, 0xB9, 0x19, 0x17,
+0x3E, 0x45, 0x1D, 0x18, 0xF2, 0x29, 0x6A, 0x59, 0xA4, 0x29, 0xCA, 0xC9, 0x75, 0xC5, 0x95, 0x90,
+0x8F, 0x15, 0x31, 0xD9, 0x93, 0xA5, 0x94, 0x55, 0x5C, 0x56, 0x40, 0x16, 0x5A, 0xA3, 0x51, 0xD3,
+0x27, 0x05, 0xE0, 0xA4, 0x65, 0xF9, 0xA8, 0x14, 0x1E, 0x31, 0x01, 0x02, 0x33, 0x83, 0x41, 0x02,
+0x24, 0x72, 0xF0, 0x1D, 0xCC, 0x2A, 0xE6, 0xCA, 0xC8, 0x57, 0x90, 0x72, 0xE9, 0x67, 0xA2, 0x8E,
+0xEA, 0x4C, 0xEA, 0xF9, 0x56, 0x33, 0x8B, 0x5F, 0x2A, 0x83, 0x9F, 0xBA, 0x53, 0xE1, 0xBD, 0x69,
+0x7E, 0xD7, 0x7E, 0x23, 0x9C, 0x52, 0x69, 0x35, 0x5F, 0xEA, 0xB4, 0xEA, 0x5E, 0x75, 0x7F, 0x18,
+0x2A, 0x59, 0x0E, 0x61, 0x01, 0x4F, 0x93, 0xDB, 0x15, 0x8B, 0xB4, 0xAB, 0xD4, 0x06, 0xD9, 0x94,
+0xDD, 0x85, 0xEE, 0x02, 0x17, 0x98, 0xD8, 0xFD, 0x95, 0x8E, 0xE8, 0xCF, 0xC4, 0x5F, 0x32, 0x7E,
+0x13, 0xB9, 0xAE, 0x78, 0xA1, 0xA9, 0xB0, 0xF4, 0x70, 0xA4, 0xB7, 0xB5, 0x86, 0x85, 0xC1, 0xA7,
+0xF2, 0xEE, 0xCA, 0x38, 0xCF, 0x7F, 0x42, 0x67, 0xA5, 0xFF, 0xCD, 0x48, 0x4E, 0x57, 0x73, 0x19,
+0xC3, 0x2B, 0xC2, 0x55, 0x1A, 0x97, 0x93, 0x32, 0xD5, 0xD1, 0xDC, 0xD0, 0x28, 0x24, 0x8D, 0x3C,
+0x3A, 0xB9, 0x1E, 0xB6, 0xAF, 0x09, 0x8C, 0x01, 0x42, 0x0E, 0x1D, 0x02, 0x06, 0x34, 0x18, 0x3B,
+0x84, 0x8F, 0x4E, 0xC6, 0xE3, 0x8B, 0xB3, 0x9D, 0x46, 0xBA, 0xE7, 0x07, 0xD3, 0xE2, 0xF5, 0xCA,
+0xA0, 0x3A, 0xEA, 0x95, 0xF6, 0x4B, 0xB8, 0x43, 0x76, 0xEC, 0x55, 0xC9, 0x4A, 0x97, 0x69, 0x46,
+0xFD, 0x64, 0x0C, 0xB3, 0x59, 0x14, 0x2E, 0x69, 0x02, 0x1E, 0x3E, 0xDE, 0x19, 0x4A, 0xFB, 0x4A,
+0xB8, 0x94, 0xB7, 0xA6, 0x12, 0x53, 0x61, 0x77, 0x52, 0x0D, 0xDF, 0x55, 0x2B, 0xB4, 0x61, 0x7A,
+0x45, 0x26, 0xD3, 0x50, 0xB3, 0x6C, 0xDB, 0x52, 0x55, 0x21, 0xAD, 0x52, 0xD6, 0xAD, 0x30, 0x16,
+0x4B, 0xDA, 0x1D, 0xEA, 0x0E, 0x5A, 0xFD, 0x96, 0x4C, 0x0A, 0x83, 0x16, 0x08, 0x6B, 0x69, 0xFB,
+0xD5, 0xF1, 0xAA, 0x24, 0x29, 0x89, 0x9E, 0x94, 0x51, 0x29, 0xCA, 0xFA, 0x24, 0x39, 0x39, 0x93,
+0x92, 0xE8, 0x1C, 0xC4, 0xFB, 0xCC, 0x6B, 0x45, 0x1C, 0x0F, 0xAA, 0x19, 0xC6, 0xB7, 0xEA, 0xE9,
+0xCF, 0x5B, 0xB9, 0x50, 0xC6, 0x76, 0x5C, 0x07, 0x31, 0xD4, 0x0D, 0xF1, 0xFC, 0x09, 0x26, 0x3A,
+0x7B, 0xAB, 0x78, 0x81, 0xEF, 0xCA, 0xFD, 0x97, 0xA1, 0xFA, 0xC6, 0x33, 0x4F, 0xFE, 0x09, 0x6B,
+0x9C, 0x79, 0x0A, 0x17, 0x98, 0x1B, 0xCE, 0xE7, 0x92, 0x99, 0x55, 0x7E, 0x75, 0xBE, 0xD5, 0xD9,
+0xE9, 0x3A, 0xB2, 0x58, 0x4D, 0xA9, 0x95, 0xCD, 0x5A, 0xA5, 0xF4, 0xAD, 0xAA, 0x32, 0x02, 0xA6,
+0xCF, 0x49, 0xD1, 0xAD, 0x70, 0xB0, 0x9C, 0x79, 0xBF, 0x69, 0x41, 0x30, 0x0C, 0xDB, 0x13, 0x09,
+0x0C, 0x9B, 0xCD, 0xD4, 0x64, 0xC4, 0x91, 0xC5, 0x61, 0xD1, 0xAC, 0x16, 0x52, 0xD8, 0x49, 0x33,
+0x23, 0x57, 0xA5, 0x31, 0x45, 0xF3, 0x4D, 0x87, 0x55, 0xEE, 0x51, 0xBA, 0x8E, 0xA9, 0x5C, 0xEB,
+0x36, 0x07, 0xCB, 0xB9, 0x34, 0x05, 0xC5, 0xB6, 0x7C, 0x27, 0x6E, 0x2D, 0x14, 0x2D, 0x68, 0xC7,
+0x16, 0xDA, 0xB7, 0xD9, 0xB5, 0x23, 0x65, 0x0C, 0x4A, 0xAC, 0xF9, 0x4E, 0x9C, 0x9B, 0xAB, 0x77,
+0xD0, 0xAE, 0xCD, 0xB5, 0x6E, 0xB3, 0x63, 0x95, 0x15, 0xE8, 0x83, 0xCE, 0xCD, 0x97, 0xD2, 0xB0,
+0xEF, 0xC4, 0xB5, 0xC5, 0xEA, 0x92, 0x68, 0x41, 0x5D, 0xBC, 0x50, 0x18, 0xE5, 0xD3, 0x7B, 0xEC,
+0x5B, 0xED, 0xFF, 0x8B, 0xD8, 0x58, 0x34, 0xA1, 0x0E, 0x61, 0x00, 0x56, 0xFB, 0x3D, 0x75, 0x03,
+0x9F, 0x88, 0x66, 0xCB, 0x8B, 0x14, 0xCA, 0x7A, 0x1A, 0x10, 0x56, 0x4D, 0xBF, 0x90, 0x25, 0xD1,
+0xD1, 0x5B, 0x23, 0xAA, 0xD6, 0xB2, 0x55, 0xDC, 0xC4, 0xC8, 0x56, 0xDB, 0x14, 0xF0, 0x0F, 0x5B,
+0xF5, 0x1A, 0xFD, 0xE7, 0xC0, 0x99, 0xC2, 0x22, 0x1D, 0x16, 0xE5, 0x14, 0x60, 0x97, 0xF3, 0x6C,
+0xA9, 0x24, 0xD2, 0xD5, 0xE6, 0x6A, 0x4B, 0x51, 0x4E, 0x52, 0x04, 0x92, 0xFB, 0x75, 0xD2, 0x49,
+0xC4, 0x52, 0x73, 0x8E, 0x78, 0x01, 0xB2, 0x9B, 0x59, 0xA9, 0x1F, 0x44, 0x0B, 0xF5, 0x83, 0x95,
+0xCB, 0xE4, 0xAD, 0x0F, 0xF5, 0xA4, 0xD6, 0x48, 0x43, 0x9C, 0x34, 0x6C, 0x73, 0xEC, 0xBE, 0x97,
+0x56, 0x10, 0x57, 0xD6, 0x01, 0x23, 0x69, 0xCC, 0x77, 0x92, 0xB8, 0x92, 0xB2, 0x2E, 0xED, 0xCD,
+0xA4, 0x61, 0x9B, 0xBD, 0x29, 0x9F, 0x6F, 0x7F, 0x4F, 0x5E, 0x8C, 0x4A, 0x4F, 0x23, 0x27, 0x46,
+0xE7, 0xDB, 0xEC, 0xC3, 0x33, 0x69, 0x84, 0xB4, 0xE2, 0x3B, 0x73, 0xA2, 0x2E, 0xEF, 0xCD, 0xB9,
+0x52, 0xB7, 0xFE, 0x47, 0x38, 0x14, 0x9D, 0x2A, 0x63, 0xC4, 0x77, 0xE2, 0xD8, 0xA4, 0x94, 0x3A,
+0x1A, 0x31, 0xE3, 0x86, 0x6D, 0x76, 0xA7, 0x7A, 0x58, 0x75, 0xC9, 0xBE, 0xA7, 0x2E, 0x5A, 0x78,
+0x51, 0x28, 0x7A, 0x00, 0x54, 0x68, 0x2F, 0xDD, 0xCA, 0x4B, 0xDE, 0x6D, 0xDA, 0x6A, 0xC7, 0x47,
+0x66, 0x3C, 0xD2, 0x13, 0x83, 0xC9, 0xD9, 0x57, 0xDA, 0x89, 0x96, 0xA1, 0xA4, 0xDC, 0x96, 0x7B,
+0x27, 0xCF, 0xD0, 0x8B, 0x0B, 0x23, 0x5A, 0x51, 0xA8, 0x77, 0xAF, 0x9A, 0xE0, 0xB9, 0xD8, 0x1B,
+0xEA, 0xE7, 0x00, 0xE1, 0xE3, 0x15, 0xFD, 0xCC, 0x08, 0x8D, 0x7D, 0xAE, 0x56, 0x02, 0xE8, 0x96,
+0x62, 0xB5, 0x6E, 0x68, 0xB0, 0xB9, 0xAD, 0x18, 0x86, 0xFB, 0xF5, 0x7A, 0xAD, 0xA3, 0xDF, 0xEB,
+0x15, 0xF2, 0xCD, 0x74, 0x77, 0x7E, 0xD8, 0x6F, 0x35, 0xD9, 0xC8, 0x2F, 0x02, 0xB6, 0x6A, 0xBF,
+0x3C, 0x4B, 0x9D, 0xC0, 0xEB, 0x50, 0x0B, 0xD6, 0x42, 0x4D, 0xE5, 0xC4, 0x1C, 0x1E, 0xD8, 0x61,
+0x0B, 0xFC, 0x1E, 0xDE, 0x81, 0x0B, 0x2C, 0x57, 0x8C, 0xB9, 0xAA, 0xA4, 0x3E, 0x3D, 0xDC, 0xAA,
+0x86, 0x4D, 0x85, 0x3D, 0xA8, 0xC7, 0x16, 0xB8, 0x35, 0xEE, 0xC1, 0xF9, 0xCF, 0xFA, 0x23, 0xB3,
+0x0A, 0xE9, 0x8D, 0x34, 0x6D, 0x92, 0xD8, 0xB3, 0xF4, 0xB5, 0x7D, 0xBE, 0x40, 0x9E, 0xCB, 0x01,
+0xEB, 0x6A, 0x57, 0xDF, 0xC9, 0x36, 0xF1, 0xCA, 0xE4, 0x3A, 0x62, 0x17, 0xBE, 0x31, 0x1F, 0xBE,
+0xE9, 0x5F, 0xF2, 0x22, 0xFD, 0x7E, 0x5F, 0xFE, 0xBC, 0x91, 0xBB, 0x14, 0x1D, 0x65, 0x41, 0xFC,
+0xF5, 0x1D, 0x9B, 0xC8, 0x0D, 0x65, 0x9F, 0x45, 0x69, 0xE1, 0x55, 0xDF, 0xBB, 0x53, 0xCF, 0x44,
+0xAE, 0xC7, 0xE3, 0x8B, 0xF0, 0xD9, 0x07, 0xE0, 0x0A, 0x04, 0x43, 0xED, 0x7D, 0x14, 0x37, 0x00,
+0xD1, 0x18, 0xA4, 0xCB, 0xC7, 0x6F, 0x3A, 0x55, 0xC5, 0xF4, 0x9B, 0x04, 0xE5, 0x5A, 0x39, 0x26,
+0xD1, 0x3C, 0x46, 0xAD, 0x04, 0xA9, 0x7E, 0x7F, 0x36, 0xEB, 0xF7, 0xE5, 0x33, 0x1E, 0x30, 0x50,
+0x93, 0x95, 0xC2, 0xD6, 0xD9, 0xEF, 0xCB, 0xC7, 0xD7, 0x9D, 0x83, 0x7E, 0x64, 0x5D, 0x52, 0xCF,
+0x21, 0xCB, 0x14, 0x0A, 0xB6, 0x9F, 0xDF, 0x99, 0xC4, 0xB6, 0xE1, 0xF6, 0xB0, 0x45, 0x2A, 0x5F,
+0x51, 0x33, 0xB9, 0xB9, 0xF6, 0x18, 0xCF, 0x66, 0x18, 0x37, 0xD1, 0xFE, 0x60, 0x57, 0x69, 0xFF,
+0xB2, 0x5F, 0xED, 0xAC, 0xB7, 0x8C, 0x59, 0x5F, 0x51, 0xD7, 0xD9, 0xAC, 0x29, 0xD2, 0x2F, 0x43,
+0x5D, 0x5F, 0xD5, 0xE8, 0x3A, 0xC2, 0x94, 0x7F, 0x55, 0x5D, 0x5F, 0xBF, 0x6E, 0xA6, 0xEB, 0xAB,
+0x50, 0xD7, 0xD7, 0x35, 0xBA, 0x5E, 0x31, 0xF6, 0x75, 0x75, 0xED, 0xF7, 0x1B, 0xE9, 0xFA, 0xD4,
+0xF6, 0xDF, 0xD4, 0x6B, 0xFA, 0xD1, 0xE5, 0xC4, 0xA6, 0x32, 0x6D, 0x25, 0xFA, 0xAE, 0x9B, 0x92,
+0xAB, 0xCA, 0x2A, 0xAA, 0xEF, 0x68, 0x9C, 0x0C, 0x1A, 0xEA, 0x93, 0xE8, 0xD0, 0x6C, 0x6A, 0x25,
+0xE7, 0x68, 0xEA, 0xD1, 0xB0, 0x42, 0xB4, 0xE9, 0x1C, 0xEA, 0xD7, 0x05, 0xB5, 0x89, 0x2A, 0x55,
+0xBC, 0x25, 0xCF, 0x51, 0x58, 0x42, 0xE7, 0x88, 0xB9, 0x78, 0x8E, 0x3C, 0xAE, 0xBE, 0x53, 0x07,
+0xA9, 0xFA, 0x6B, 0x81, 0x9E, 0xA2, 0xD4, 0xCB, 0x5D, 0x14, 0xFE, 0xCC, 0x5D, 0xC6, 0x61, 0x16,
+0xDB, 0xA8, 0xC8, 0x40, 0xE9, 0xD8, 0xB8, 0xBA, 0xA2, 0x70, 0xE7, 0xDA, 0x93, 0x32, 0x2D, 0x64,
+0xEF, 0x00, 0x64, 0xA4, 0x8A, 0x55, 0x5A, 0xFA, 0x35, 0xC8, 0xD6, 0x10, 0x26, 0xB3, 0x48, 0x01,
+0x76, 0x2A, 0xC1, 0x8A, 0xE6, 0x09, 0xEB, 0x8F, 0xAC, 0xC3, 0x4C, 0x95, 0x8A, 0x42, 0x5E, 0x55,
+0xA9, 0xC4, 0x6F, 0x63, 0xEA, 0x89, 0x51, 0x7C, 0xAA, 0x37, 0xC0, 0x7F, 0xDC, 0x1F, 0xED, 0x9F,
+0x8E, 0x4E, 0x8C, 0x75, 0x44, 0xAE, 0x11, 0xC7, 0x6B, 0x23, 0x96, 0x41, 0x29, 0x7E, 0x19, 0xB3,
+0x35, 0xFC, 0x15, 0x73, 0x47, 0xC6, 0x88, 0xAC, 0x35, 0x78, 0x1C, 0x8C, 0x52, 0x95, 0x3C, 0x89,
+0x1C, 0x5D, 0xC2, 0x93, 0x6A, 0xC8, 0xD4, 0xEE, 0xEC, 0x1D, 0x1C, 0x64, 0x6B, 0x77, 0xBE, 0x45,
+0xD4, 0xCC, 0x04, 0x35, 0x08, 0x2A, 0xEB, 0xAB, 0xA1, 0x66, 0xE6, 0x51, 0x33, 0xFF, 0x7D, 0xA8,
+0x35, 0xCF, 0x93, 0x47, 0x3F, 0xAD, 0x2C, 0x44, 0x6A, 0xBA, 0xBF, 0x21, 0xBB, 0x57, 0xEA, 0xCB,
+0x4A, 0x1E, 0xB4, 0x1E, 0x8D, 0xF8, 0xAC, 0x53, 0x57, 0xA5, 0xEE, 0x3D, 0x19, 0x9E, 0x06, 0xC2,
+0x67, 0x0E, 0x15, 0x24, 0x95, 0x74, 0xD5, 0x93, 0xDB, 0x30, 0x61, 0xAA, 0x19, 0x62, 0xA3, 0xC4,
+0xD8, 0x4E, 0x6A, 0xE2, 0xA2, 0x62, 0x1C, 0xE0, 0x41, 0x6D, 0x1B, 0xA9, 0x37, 0x67, 0x88, 0xB5,
+0xF3, 0x4D, 0x27, 0xD9, 0x5D, 0x29, 0xA3, 0x2A, 0x0D, 0x46, 0xAF, 0xCC, 0xEA, 0x34, 0x18, 0x9F,
+0x46, 0x69, 0x70, 0x34, 0x3A, 0x3E, 0xE8, 0xF7, 0xD7, 0x4A, 0x83, 0x91, 0xF8, 0x6C, 0xCA, 0x0A,
+0x19, 0x43, 0xC2, 0xA2, 0x23, 0x8A, 0x54, 0xA9, 0x3D, 0xEA, 0xA1, 0xB1, 0x89, 0x5D, 0x57, 0xED,
+0xAF, 0xAD, 0xDD, 0x0B, 0xBF, 0x66, 0xDA, 0x68, 0x84, 0x5C, 0xF2, 0x4A, 0x70, 0xA6, 0x88, 0x25,
+0x83, 0x5E, 0xBF, 0x3F, 0x1A, 0x3D, 0x06, 0x7A, 0x31, 0xEB, 0x96, 0xAE, 0x2E, 0x91, 0xBB, 0x53,
+0xDB, 0x07, 0x59, 0xFC, 0x9E, 0xB3, 0x46, 0x2C, 0x39, 0x4F, 0x00, 0x93, 0x90, 0x6D, 0x02, 0x58,
+0x06, 0xAF, 0x88, 0x71, 0x6B, 0x78, 0x25, 0x8F, 0x50, 0xFB, 0xAD, 0x7A, 0x11, 0x01, 0xFA, 0xFE,
+0x47, 0x41, 0xF8, 0xCE, 0x36, 0x62, 0x97, 0x7D, 0x8F, 0x3B, 0x0E, 0xB9, 0x4C, 0xE3, 0xC3, 0x51,
+0xCC, 0x87, 0x5D, 0x8A, 0xBD, 0x7A, 0xC3, 0x47, 0xCE, 0x60, 0xE5, 0x39, 0x0A, 0xEB, 0xD7, 0xDA,
+0x21, 0xBC, 0x32, 0xA9, 0x06, 0xFF, 0x2A, 0x60, 0x1F, 0x1F, 0xDA, 0xEC, 0xCB, 0xEB, 0x1A, 0xDA,
+0x5C, 0xE3, 0x23, 0x07, 0x68, 0x86, 0x7B, 0x6B, 0xF8, 0xB3, 0x3A, 0x45, 0xA7, 0x70, 0xFE, 0x6F,
+0xC1, 0x74, 0x0D, 0x33, 0x1A, 0x21, 0x9A, 0x7D, 0x51, 0x5F, 0x23, 0x9A, 0x6B, 0x4C, 0x46, 0x18,
+0x89, 0xE9, 0xC3, 0x83, 0x35, 0xC3, 0xBE, 0x35, 0xFC, 0xE9, 0xFD, 0x18, 0x86, 0x99, 0x5B, 0x22,
+0xBF, 0xE4, 0xFE, 0x39, 0x1A, 0x9F, 0x5F, 0x5F, 0x7C, 0xF8, 0x38, 0xDE, 0xCE, 0xF8, 0x4C, 0x7F,
+0x21, 0x41, 0x82, 0x65, 0xD2, 0xF4, 0x70, 0x24, 0xF3, 0x40, 0x46, 0xBC, 0xF3, 0x30, 0x8E, 0x8E,
+0x27, 0xC7, 0x97, 0xDB, 0x18, 0x90, 0xC5, 0x6F, 0x5C, 0x88, 0x33, 0x68, 0xE1, 0xC2, 0x63, 0x07,
+0x66, 0x41, 0x84, 0xCC, 0xA4, 0x61, 0x13, 0x0A, 0xDB, 0xB6, 0x33, 0x2C, 0xB3, 0xDF, 0x2B, 0x11,
+0xE1, 0x99, 0x6D, 0x7C, 0xE4, 0xD0, 0xCC, 0x70, 0x07, 0x18, 0xE5, 0x29, 0x52, 0xE7, 0xE8, 0x9A,
+0x38, 0xF0, 0x7B, 0x2B, 0xA7, 0x45, 0xD9, 0xAF, 0xCE, 0xC8, 0x8C, 0x3F, 0x71, 0xE3, 0x63, 0x07,
+0x65, 0x86, 0x7D, 0x3C, 0x00, 0xC9, 0x73, 0x34, 0xC2, 0xD4, 0xDE, 0xCE, 0x88, 0x4C, 0x7D, 0x3B,
+0x88, 0x46, 0x31, 0xDD, 0xF2, 0xC8, 0xB1, 0x98, 0xB0, 0x6E, 0x0D, 0x4F, 0x60, 0x81, 0xFA, 0x2F,
+0xC0, 0xAE, 0xD9, 0x6A, 0xFE, 0x01, 0x8F, 0xA4, 0x57, 0xBE, 0xC4, 0x96, 0xBD, 0x76, 0xD4, 0x93,
+0xAF, 0xE3, 0xE5, 0x6E, 0x38, 0xFA, 0xA1, 0xD3, 0x39, 0xD2, 0xDF, 0xA0, 0x1F, 0x3E, 0x93, 0x0C,
+0x4F, 0x54, 0xD1, 0x80, 0x4D, 0xCD, 0x1B, 0xB9, 0xCA, 0x54, 0x5F, 0x63, 0x62, 0xB3, 0xB0, 0x3E,
+0xBE, 0xAB, 0xFE, 0x7F, 0x9B, 0x56, 0x2F, 0x2C, 0x14, 0x6E, 0xBD, 0x31, 0x86, 0x1F, 0xD5, 0x11,
+0x4A, 0xBF, 0xF6, 0x1E, 0x32, 0x19, 0x76, 0x3A, 0x29, 0x71, 0x69, 0x4B, 0xA3, 0x63, 0xA0, 0x0C,
+0xBF, 0x2E, 0x40, 0x7D, 0x87, 0x40, 0xF8, 0x9F, 0xEC, 0xFC, 0x3F, 0x2D, 0x9C, 0x8E, 0x40, 0x7E,
+0x67, 0x00, 0x00
};
\ No newline at end of file
diff --git a/src/www/setuppage.html b/src/www/setuppage.html
index d258569..d11264b 100644
--- a/src/www/setuppage.html
+++ b/src/www/setuppage.html
@@ -13,7 +13,7 @@
flex-direction: column;
justify-content: center;
align-items: center;
- height: 100vh;
+ height: calc(100% - 100px);
}
.logo-container {
display: flex;
@@ -33,7 +33,7 @@
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
- width: 60%;
+ width: 80%;
margin-top: 20px;
}
label {
@@ -134,6 +134,31 @@
}