diff options
61 files changed, 542 insertions, 1464 deletions
@@ -12,8 +12,10 @@ __pycache__ /esp32-cam/CameraWebServer/wifi_password.h cmake-build-* .pio +platformio.ini CMakeListsPrivate.txt - +/platformio/*/CMakeLists.txt +/platformio/*/CMakeListsPrivate.txt *.swp /localwebsite/vendor @@ -23,4 +25,4 @@ CMakeListsPrivate.txt /localwebsite/test.php /watchos/InfiniSolar/Pods -xcuserdata
\ No newline at end of file +xcuserdata diff --git a/platformio/temphum/src/logging.h b/platformio/common/include/homekit/logging.h index 070f367..559ca33 100644 --- a/platformio/temphum/src/logging.h +++ b/platformio/common/include/homekit/logging.h @@ -1,7 +1,7 @@ -#pragma once +#ifndef COMMON_HOMEKIT_LOGGING_H +#define COMMON_HOMEKIT_LOGGING_H #include <stdlib.h> -#include "config.def.h" #ifdef DEBUG @@ -16,3 +16,5 @@ #define PRINTF(...) #endif + +#endif //COMMON_HOMEKIT_LOGGING_H
\ No newline at end of file diff --git a/platformio/common/include/homekit/macros.h b/platformio/common/include/homekit/macros.h new file mode 100644 index 0000000..7d3ad83 --- /dev/null +++ b/platformio/common/include/homekit/macros.h @@ -0,0 +1 @@ +#define ARRAY_SIZE(X) sizeof((X))/sizeof((X)[0])
\ No newline at end of file diff --git a/platformio/relayctl/src/stopwatch.h b/platformio/common/include/homekit/stopwatch.h index bac2fcc..bac2fcc 100644 --- a/platformio/relayctl/src/stopwatch.h +++ b/platformio/common/include/homekit/stopwatch.h diff --git a/platformio/relayctl/src/util.h b/platformio/common/include/homekit/util.h index e0780d8..e0780d8 100644 --- a/platformio/relayctl/src/util.h +++ b/platformio/common/include/homekit/util.h diff --git a/platformio/temphum/src/config.cpp b/platformio/common/libs/config/homekit/config.cpp index 54922c1..5bafcad 100644 --- a/platformio/temphum/src/config.cpp +++ b/platformio/common/libs/config/homekit/config.cpp @@ -1,7 +1,7 @@ #include <EEPROM.h> #include <strings.h> #include "config.h" -#include "logging.h" +#include <homekit/logging.h> #define GET_DATA_CRC(data) \ eeprom_crc(reinterpret_cast<uint8_t*>(&(data))+4, sizeof(ConfigData)-4) @@ -81,4 +81,4 @@ char* ConfigData::escapeHomeId(char* buf, size_t len) { return buf; } -}
\ No newline at end of file +} diff --git a/platformio/temphum/src/config.h b/platformio/common/libs/config/homekit/config.h index 2a5b36a..28f01fb 100644 --- a/platformio/temphum/src/config.h +++ b/platformio/common/libs/config/homekit/config.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef COMMON_HOMEKIT_CONFIG_H +#define COMMON_HOMEKIT_CONFIG_H #include <Arduino.h> @@ -31,4 +32,6 @@ void erase(ConfigData& data); bool isValid(ConfigData& data); bool isDirty(ConfigData& data); -}
\ No newline at end of file +} + +#endif //COMMON_HOMEKIT_CONFIG_H
\ No newline at end of file diff --git a/platformio/common/libs/config/library.json b/platformio/common/libs/config/library.json new file mode 100644 index 0000000..720d093 --- /dev/null +++ b/platformio/common/libs/config/library.json @@ -0,0 +1,8 @@ +{ + "name": "homekit_config", + "version": "1.0.2", + "build": { + "flags": "-I../../include" + } +} + diff --git a/platformio/temphum/src/http_server.cpp b/platformio/common/libs/http_server/homekit/http_server.cpp index 5fbcb8a..ea81f5b 100644 --- a/platformio/temphum/src/http_server.cpp +++ b/platformio/common/libs/http_server/homekit/http_server.cpp @@ -1,13 +1,13 @@ +#include "http_server.h" + #include <Arduino.h> #include <string.h> -#include "static.h" -#include "http_server.h" -#include "config.h" -#include "config.def.h" -#include "logging.h" -#include "util.h" -#include "led.h" +#include <homekit/static.h> +#include <homekit/config.h> +#include <homekit/logging.h> +#include <homekit/macros.h> +#include <homekit/util.h> namespace homekit { @@ -64,7 +64,7 @@ void HttpServer::start() { if (!isValid(cfg) || !cfg.flags.node_configured) { sprintf_P(json_buf, JSON_STATUS_FMT - , DEFAULT_NODE_ID + , CONFIG_NODE_ID #ifdef DEBUG , 0 , cfg.crc @@ -215,7 +215,8 @@ void HttpServer::start() { return; PRINTF("http/ota: writing %ul\n", upload.currentSize); - esp_led.blink(1, 1); + ota_led(); + if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { #ifdef DEBUG Update.printError(Serial); @@ -276,4 +277,6 @@ bool HttpServer::getInputParam(const char *field_name, return true; } -}
\ No newline at end of file +void HttpServer::ota_led() const {} + +} diff --git a/platformio/relayctl/src/http_server.h b/platformio/common/libs/http_server/homekit/http_server.h index 35f7c08..8725a88 100644 --- a/platformio/relayctl/src/http_server.h +++ b/platformio/common/libs/http_server/homekit/http_server.h @@ -1,12 +1,15 @@ -#pragma once +#ifndef COMMON_HOMEKIT_HTTP_SERVER_H +#define COMMON_HOMEKIT_HTTP_SERVER_H + #include <ESP8266WebServer.h> #include <Ticker.h> #include <memory> #include <list> #include <utility> -#include "config.h" -#include "wifi.h" -#include "static.h" + +#include <homekit/config.h> +#include <homekit/wifi.h> +#include <homekit/static.h> namespace homekit { @@ -36,6 +39,7 @@ private: void sendError(const String& message); bool getInputParam(const char* field_name, size_t max_len, String& dst); + virtual void ota_led() const; public: explicit HttpServer(std::shared_ptr<std::list<wifi::ScanResult>> scanResults) @@ -53,4 +57,6 @@ public: void loop(); }; -}
\ No newline at end of file +} + +#endif //COMMON_HOMEKIT_HTTP_SERVER_H diff --git a/platformio/common/libs/http_server/library.json b/platformio/common/libs/http_server/library.json new file mode 100644 index 0000000..ee2d369 --- /dev/null +++ b/platformio/common/libs/http_server/library.json @@ -0,0 +1,8 @@ +{ + "name": "homekit_http_server", + "version": "1.0.3", + "build": { + "flags": "-I../../include" + } +} + diff --git a/platformio/common/libs/led/homekit/led.cpp b/platformio/common/libs/led/homekit/led.cpp new file mode 100644 index 0000000..acc2140 --- /dev/null +++ b/platformio/common/libs/led/homekit/led.cpp @@ -0,0 +1,20 @@ +#include "led.h" + +namespace homekit { + +void Led::on_off(uint16_t delay_ms, bool last_delay) const { + on(); + delay(delay_ms); + + off(); + if (last_delay) + delay(delay_ms); +} + +void Led::blink(uint8_t count, uint16_t delay_ms) const { + for (uint8_t i = 0; i < count; i++) { + on_off(delay_ms, i < count-1); + } +} + +} diff --git a/platformio/temphum/src/led.h b/platformio/common/libs/led/homekit/led.h index 315523a..513bfea 100644 --- a/platformio/temphum/src/led.h +++ b/platformio/common/libs/led/homekit/led.h @@ -1,6 +1,8 @@ -#pragma once +#ifndef COMMON_HOMEKIT_LED_H +#define COMMON_HOMEKIT_LED_H #include <Arduino.h> +#include <stdint.h> namespace homekit { @@ -17,23 +19,10 @@ public: inline void off() const { digitalWrite(_pin, HIGH); } inline void on() const { digitalWrite(_pin, LOW); } - void on_off(uint16_t delay_ms, bool last_delay = false) const { - on(); - delay(delay_ms); - - off(); - if (last_delay) - delay(delay_ms); - } - - void blink(uint8_t count, uint16_t delay_ms) const { - for (uint8_t i = 0; i < count; i++) { - on_off(delay_ms, i < count-1); - } - } + void on_off(uint16_t delay_ms, bool last_delay = false) const; + void blink(uint8_t count, uint16_t delay_ms) const; }; -extern Led board_led; -extern Led esp_led; +} -}
\ No newline at end of file +#endif //COMMON_HOMEKIT_LED_H diff --git a/platformio/common/libs/led/library.json b/platformio/common/libs/led/library.json new file mode 100644 index 0000000..69a3ac3 --- /dev/null +++ b/platformio/common/libs/led/library.json @@ -0,0 +1,8 @@ +{ + "name": "homekit_led", + "version": "1.0.6", + "build": { + "flags": "-I../../include" + } +} + diff --git a/platformio/common/libs/mqtt/homekit/mqtt.cpp b/platformio/common/libs/mqtt/homekit/mqtt.cpp new file mode 100644 index 0000000..c2ba293 --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt.cpp @@ -0,0 +1,18 @@ +#include "./mqtt.h" + +namespace homekit::mqtt { + + const uint8_t MQTT_CA_FINGERPRINT[] = { \ + 0x0e, 0xb6, 0x3a, 0x02, 0x1f, \ + 0x4e, 0x1e, 0xe1, 0x6a, 0x67, \ + 0x62, 0xec, 0x64, 0xd4, 0x84, \ + 0x8a, 0xb0, 0xc9, 0x9c, 0xbb \ + };; + const char MQTT_SERVER[] = "mqtt.solarmon.ru"; + const uint16_t MQTT_PORT = 8883; + const char MQTT_USERNAME[] = CONFIG_MQTT_USERNAME; + const char MQTT_PASSWORD[] = CONFIG_MQTT_PASSWORD; + const char MQTT_CLIENT_ID[] = CONFIG_MQTT_CLIENT_ID; + const char MQTT_SECRET[CONFIG_NODE_SECRET_SIZE+1] = CONFIG_NODE_SECRET; + +} diff --git a/platformio/common/libs/mqtt/homekit/mqtt.h b/platformio/common/libs/mqtt/homekit/mqtt.h new file mode 100644 index 0000000..2c86b00 --- /dev/null +++ b/platformio/common/libs/mqtt/homekit/mqtt.h @@ -0,0 +1,18 @@ +#ifndef COMMON_HOMEKIT_MQTT_H +#define COMMON_HOMEKIT_MQTT_H + +#include <stdint.h> + +namespace homekit::mqtt { + + extern const uint8_t MQTT_CA_FINGERPRINT[]; + extern const char MQTT_SERVER[]; + extern const uint16_t MQTT_PORT; + extern const char MQTT_USERNAME[]; + extern const char MQTT_PASSWORD[]; + extern const char MQTT_CLIENT_ID[]; + extern const char MQTT_SECRET[CONFIG_NODE_SECRET_SIZE+1]; + +} + +#endif //COMMON_HOMEKIT_MQTT_H diff --git a/platformio/common/libs/mqtt/library.json b/platformio/common/libs/mqtt/library.json new file mode 100644 index 0000000..8131494 --- /dev/null +++ b/platformio/common/libs/mqtt/library.json @@ -0,0 +1,8 @@ +{ + "name": "homekit_mqtt", + "version": "1.0.2", + "build": { + "flags": "-I../../include" + } +} + diff --git a/platformio/temphum/src/static.cpp b/platformio/common/libs/static/homekit/static.cpp index 366a09f..366a09f 100644 --- a/platformio/temphum/src/static.cpp +++ b/platformio/common/libs/static/homekit/static.cpp diff --git a/platformio/temphum/src/static.h b/platformio/common/libs/static/homekit/static.h index 90560bf..c2617e9 100644 --- a/platformio/temphum/src/static.h +++ b/platformio/common/libs/static/homekit/static.h @@ -2,7 +2,8 @@ * This file is autogenerated with make_static.sh script */ -#pragma once +#ifndef COMMON_HOMEKIT_STATIC_H +#define COMMON_HOMEKIT_STATIC_H #include <stdlib.h> @@ -20,3 +21,5 @@ extern const StaticFile style_css; extern const StaticFile favicon_ico; } + +#endif //COMMON_HOMEKIT_STATIC_H
\ No newline at end of file diff --git a/platformio/common/libs/static/library.json b/platformio/common/libs/static/library.json new file mode 100644 index 0000000..bc650d7 --- /dev/null +++ b/platformio/common/libs/static/library.json @@ -0,0 +1,8 @@ +{ + "name": "homekit_static", + "version": "1.0.1", + "build": { + "flags": "-I../../include" + } +} + diff --git a/platformio/temphum/src/wifi.cpp b/platformio/common/libs/wifi/homekit/wifi.cpp index 3d7e092..3060dd6 100644 --- a/platformio/temphum/src/wifi.cpp +++ b/platformio/common/libs/wifi/homekit/wifi.cpp @@ -1,18 +1,17 @@ #include <pgmspace.h> -#include "config.def.h" #include "wifi.h" -#include "config.h" -#include "logging.h" +#include <homekit/config.h> +#include <homekit/logging.h> namespace homekit::wifi { using namespace homekit; using homekit::config::ConfigData; -const char NODE_ID[] = DEFAULT_NODE_ID; -const char AP_SSID[] = DEFAULT_WIFI_AP_SSID; -const char STA_SSID[] = DEFAULT_WIFI_STA_SSID; -const char STA_PSK[] = DEFAULT_WIFI_STA_PSK; +const char NODE_ID[] = CONFIG_NODE_ID; +const char AP_SSID[] = CONFIG_WIFI_AP_SSID; +const char STA_SSID[] = CONFIG_WIFI_STA_SSID; +const char STA_PSK[] = CONFIG_WIFI_STA_PSK; void getConfig(ConfigData &cfg, const char** ssid, const char** psk, const char** hostname) { if (cfg.flags.wifi_configured) { diff --git a/platformio/temphum/src/wifi.h b/platformio/common/libs/wifi/homekit/wifi.h index 1b95b2f..3fe77cb 100644 --- a/platformio/temphum/src/wifi.h +++ b/platformio/common/libs/wifi/homekit/wifi.h @@ -1,9 +1,11 @@ -#pragma once +#ifndef HOMEKIT_TEPMHUM_WIFI_H +#define HOMEKIT_TEPMHUM_WIFI_H #include <ESP8266WiFi.h> #include <list> #include <memory> -#include "config.h" + +#include <homekit/config.h> namespace homekit::wifi { @@ -33,4 +35,6 @@ extern const char STA_SSID[]; extern const char STA_PSK[]; extern const char NODE_ID[]; -}
\ No newline at end of file +} + +#endif //HOMEKIT_TEPMHUM_WIFI_H
\ No newline at end of file diff --git a/platformio/common/libs/wifi/library.json b/platformio/common/libs/wifi/library.json new file mode 100644 index 0000000..c7faecd --- /dev/null +++ b/platformio/common/libs/wifi/library.json @@ -0,0 +1,8 @@ +{ + "name": "homekit_wifi", + "version": "1.0.1", + "build": { + "flags": "-I../../include" + } +} + diff --git a/platformio/relayctl/CMakeLists.txt b/platformio/relayctl/CMakeLists.txt deleted file mode 100644 index cbc0a64..0000000 --- a/platformio/relayctl/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
-# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
-#
-# If you need to override existing CMake configuration or add extra,
-# please create `CMakeListsUser.txt` in the root of project.
-# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
-
-cmake_minimum_required(VERSION 3.13)
-set(CMAKE_SYSTEM_NAME Generic)
-set(CMAKE_C_COMPILER_WORKS 1)
-set(CMAKE_CXX_COMPILER_WORKS 1)
-
-project("relayctl" C CXX)
-
-include(CMakeListsPrivate.txt)
-
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
-include(CMakeListsUser.txt)
-endif()
-
-add_custom_target(
- Production ALL
- COMMAND platformio -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-add_custom_target(
- Debug ALL
- COMMAND platformio -c clion debug "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-add_executable(Z_DUMMY_TARGET ${SRC_LIST})
diff --git a/platformio/relayctl/platformio.ini b/platformio/relayctl/platformio.ini deleted file mode 100644 index 662049e..0000000 --- a/platformio/relayctl/platformio.ini +++ /dev/null @@ -1,23 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:esp12e] -platform = espressif8266 -board = esp12e -framework = arduino -upload_port = /dev/ttyUSB0 -monitor_speed = 115200 -lib_deps = - https://github.com/bertmelis/espMqttClient#unordered-acks -;build_flags = -; -DDEBUG -; -DDEBUG_ESP_SSL -; -DDEBUG_ESP_PORT=Serial -build_type = release
\ No newline at end of file diff --git a/platformio/relayctl/src/config.cpp b/platformio/relayctl/src/config.cpp deleted file mode 100644 index 796adf0..0000000 --- a/platformio/relayctl/src/config.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include <EEPROM.h> -#include <strings.h> -#include "config.h" -#include "logging.h" - -#define GET_DATA_CRC(data) \ - eeprom_crc(reinterpret_cast<uint8_t*>(&(data))+4, sizeof(ConfigData)-4) - -namespace homekit::config { - -static const uint32_t magic = 0xdeadbeef; -static const uint32_t crc_table[16] PROGMEM = { - 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, - 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, - 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c -}; - -static uint32_t eeprom_crc(const uint8_t* data, size_t len) { - uint32_t crc = ~0L; - for (size_t index = 0; index < len; index++) { - crc = pgm_read_word(&crc_table[(crc ^ data[index]) & 0x0f]) ^ (crc >> 4); - crc = pgm_read_word(&crc_table[(crc ^ (data[index] >> 4)) & 0x0f]) ^ (crc >> 4); - crc = ~crc; - } - return crc; -} - -ConfigData read() { - ConfigData data; - EEPROM.begin(sizeof(ConfigData)); - EEPROM.get(0, data); - EEPROM.end(); -#ifdef DEBUG - if (!isValid(data)) { - PRINTLN("config::read(): data is not valid!"); - } -#endif - return data; -} - -void write(ConfigData& data) { - EEPROM.begin(sizeof(ConfigData)); - data.magic = magic; - data.crc = GET_DATA_CRC(data); - EEPROM.put(0, data); - EEPROM.end(); -} - -void erase() { - ConfigData data; - erase(data); -} - -void erase(ConfigData& data) { - bzero(reinterpret_cast<uint8_t*>(&data), sizeof(data)); - write(data); -} - -bool isValid(ConfigData& data) { - return data.crc == GET_DATA_CRC(data); -} - -bool isDirty(ConfigData& data) { - return data.magic != magic; -} - -char* ConfigData::escapeHomeId(char* buf, size_t len) { - if (len < 32) - return nullptr; - size_t id_len = strlen(home_id); - char* c = home_id; - char* dst = buf; - for (size_t i = 0; i < id_len; i++) { - if (*c == '"') - *(dst++) = '\\'; - *(dst++) = *c; - c++; - } - *dst = '\0'; - return buf; -} - -}
\ No newline at end of file diff --git a/platformio/relayctl/src/config.def.h.example b/platformio/relayctl/src/config.def.h.example deleted file mode 100644 index 52de4f7..0000000 --- a/platformio/relayctl/src/config.def.h.example +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#define FW_VERSION 7 - -#define DEFAULT_WIFI_AP_SSID "" -#define DEFAULT_WIFI_STA_SSID "" -#define DEFAULT_WIFI_STA_PSK "" - -#define DEFAULT_MQTT_SERVER "mqtt.solarmon.ru" -#define DEFAULT_MQTT_PORT 8883 -#define DEFAULT_MQTT_USERNAME "" -#define DEFAULT_MQTT_PASSWORD "" -#define DEFAULT_MQTT_CLIENT_ID "" -#define DEFAULT_MQTT_CA_FINGERPRINT { \ - 0x0e, 0xb6, 0x3a, 0x02, 0x1f, \ - 0x4e, 0x1e, 0xe1, 0x6a, 0x67, \ - 0x62, 0xec, 0x64, 0xd4, 0x84, \ - 0x8a, 0xb0, 0xc9, 0x9c, 0xbb \ -}; - -#define DEFAULT_HOME_ID "relay-node" - -#define FLASH_BUTTON_PIN 0 -#define ESP_LED_PIN 2 -#define BOARD_LED_PIN 16 -#define RELAY_PIN 5 - -// 12 bytes string -#define HOME_SECRET_SIZE 12 -#define HOME_SECRET "" -#define MQTT_BLINK 1 - -#define ARRAY_SIZE(X) sizeof((X))/sizeof((X)[0])
\ No newline at end of file diff --git a/platformio/relayctl/src/config.h b/platformio/relayctl/src/config.h deleted file mode 100644 index 562b61a..0000000 --- a/platformio/relayctl/src/config.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include <Arduino.h> - -namespace homekit::config { - -struct ConfigFlags { - uint8_t wifi_configured: 1; - uint8_t node_configured: 1; - uint8_t reserved: 6; -} __attribute__((packed)); - -struct ConfigData { - // helpers - uint32_t crc = 0; - uint32_t magic = 0; - char home_id[16] = {0}; - char wifi_ssid[32] = {0}; - char wifi_psk[63] = {0}; - ConfigFlags flags {0}; - - // helper methods - char* escapeHomeId(char* buf, size_t len); -} __attribute__((packed)); - - -ConfigData read(); -void write(ConfigData& data); -void erase(); -void erase(ConfigData& data); -bool isValid(ConfigData& data); -bool isDirty(ConfigData& data); - -}
\ No newline at end of file diff --git a/platformio/relayctl/src/http_server.cpp b/platformio/relayctl/src/http_server.cpp deleted file mode 100644 index e1e9c10..0000000 --- a/platformio/relayctl/src/http_server.cpp +++ /dev/null @@ -1,279 +0,0 @@ -#include <Arduino.h> -#include <string.h> - -#include "static.h" -#include "http_server.h" -#include "config.h" -#include "config.def.h" -#include "logging.h" -#include "util.h" -#include "led.h" - -namespace homekit { - -using files::StaticFile; - -static const char CONTENT_TYPE_HTML[] PROGMEM = "text/html; charset=utf-8"; -static const char CONTENT_TYPE_CSS[] PROGMEM = "text/css"; -static const char CONTENT_TYPE_JS[] PROGMEM = "application/javascript"; -static const char CONTENT_TYPE_JSON[] PROGMEM = "application/json"; -static const char CONTENT_TYPE_FAVICON[] PROGMEM = "image/x-icon"; - -static const char JSON_UPDATE_FMT[] PROGMEM = "{\"result\":%d}"; -static const char JSON_STATUS_FMT[] PROGMEM = "{\"home_id\":\"%s\"" -#ifdef DEBUG - ",\"configured\":%d" - ",\"crc\":%u" - ",\"fl_n\":%d" - ",\"fl_w\":%d" -#endif - "}"; -static const size_t JSON_BUF_SIZE = 192; - -static const char JSON_SCAN_FIRST_LIST[] PROGMEM = "{\"list\":["; - -static const char MSG_IS_INVALID[] PROGMEM = " is invalid"; -static const char MSG_IS_MISSING[] PROGMEM = " is missing"; - -static const char GZIP[] PROGMEM = "gzip"; -static const char CONTENT_ENCODING[] PROGMEM = "Content-Encoding"; -static const char NOT_FOUND[] PROGMEM = "Not Found"; - -static const char ROUTE_STYLE_CSS[] PROGMEM = "/style.css"; -static const char ROUTE_APP_JS[] PROGMEM = "/app.js"; -static const char ROUTE_MD5_JS[] PROGMEM = "/md5.js"; -static const char ROUTE_FAVICON_ICO[] PROGMEM = "/favicon.ico"; -static const char ROUTE_STATUS[] PROGMEM = "/status"; -static const char ROUTE_SCAN[] PROGMEM = "/scan"; -static const char ROUTE_RESET[] PROGMEM = "/reset"; -// #ifdef DEBUG -static const char ROUTE_HEAP[] PROGMEM = "/heap"; -// #endif -static const char ROUTE_UPDATE[] PROGMEM = "/update"; - -void HttpServer::start() { - server.on(FPSTR(ROUTE_STYLE_CSS), HTTP_GET, [&]() { sendGzip(files::style_css, CONTENT_TYPE_CSS); }); - server.on(FPSTR(ROUTE_APP_JS), HTTP_GET, [&]() { sendGzip(files::app_js, CONTENT_TYPE_JS); }); - server.on(FPSTR(ROUTE_MD5_JS), HTTP_GET, [&]() { sendGzip(files::md5_js, CONTENT_TYPE_JS); }); - server.on(FPSTR(ROUTE_FAVICON_ICO), HTTP_GET, [&]() { sendGzip(files::favicon_ico, CONTENT_TYPE_FAVICON); }); - - server.on("/", HTTP_GET, [&]() { sendGzip(files::index_html, CONTENT_TYPE_HTML); }); - server.on(FPSTR(ROUTE_STATUS), HTTP_GET, [&]() { - char json_buf[JSON_BUF_SIZE]; - auto cfg = config::read(); - - if (!isValid(cfg) || !cfg.flags.node_configured) { - sprintf_P(json_buf, JSON_STATUS_FMT - , DEFAULT_HOME_ID -#ifdef DEBUG - , 0 - , cfg.crc - , cfg.flags.node_configured - , cfg.flags.wifi_configured -#endif - ); - } else { - char escaped_home_id[32]; - char *escaped_home_id_res = cfg.escapeHomeId(escaped_home_id, 32); - sprintf_P(json_buf, JSON_STATUS_FMT - , escaped_home_id_res == nullptr ? "?" : escaped_home_id -#ifdef DEBUG - , 1 - , cfg.crc - , cfg.flags.node_configured - , cfg.flags.wifi_configured -#endif - ); - } - server.send(200, FPSTR(CONTENT_TYPE_JSON), json_buf); - }); - server.on(FPSTR(ROUTE_STATUS), HTTP_POST, [&]() { - auto cfg = config::read(); - String s; - - if (!getInputParam("ssid", 32, s)) return; - strncpy(cfg.wifi_ssid, s.c_str(), 32); - PRINTF("saving ssid: %s\n", cfg.wifi_ssid); - - if (!getInputParam("psk", 63, s)) return; - strncpy(cfg.wifi_psk, s.c_str(), 63); - PRINTF("saving psk: %s\n", cfg.wifi_psk); - - if (!getInputParam("hid", 16, s)) return; - strcpy(cfg.home_id, s.c_str()); - PRINTF("saving home id: %s\n", cfg.home_id); - - cfg.flags.node_configured = 1; - cfg.flags.wifi_configured = 1; - - config::write(cfg); - - restartTimer.once(0, restart); - }); - - server.on(FPSTR(ROUTE_RESET), HTTP_POST, [&]() { - config::erase(); - restartTimer.once(1, restart); - }); - - server.on(FPSTR(ROUTE_HEAP), HTTP_GET, [&]() { - server.send(200, FPSTR(CONTENT_TYPE_HTML), String(ESP.getFreeHeap())); - }); - - server.on(FPSTR(ROUTE_SCAN), HTTP_GET, [&]() { - size_t i = 0; - size_t len; - const char* ssid; - bool enough = false; - - bzero(reinterpret_cast<uint8_t*>(scanBuf), scanBufSize); - char* cur = scanBuf; - - strncpy_P(cur, JSON_SCAN_FIRST_LIST, scanBufSize); - cur += 9; - - for (auto& res: *scanResults) { - ssid = res.ssid.c_str(); - len = res.ssid.length(); - - // new item (array with 2 items) - *cur++ = '['; - - // 1. ssid (string) - *cur++ = '"'; - for (size_t j = 0; j < len; j++) { - if (*(ssid+j) == '"') - *cur++ = '\\'; - *cur++ = *(ssid+j); - } - *cur++ = '"'; - *cur++ = ','; - - // 2. rssi (number) - cur += sprintf(cur, "%d", res.rssi); - - // close array - *cur++ = ']'; - - if ((size_t)(cur - scanBuf) >= (size_t) ARRAY_SIZE(scanBuf) - 40) - enough = true; - - if (i < scanResults->size() - 1 || enough) - *cur++ = ','; - - if (enough) - break; - - i++; - } - - *cur++ = ']'; - *cur++ = '}'; - *cur++ = '\0'; - - server.send(200, FPSTR(CONTENT_TYPE_JSON), scanBuf); - }); - - server.on(FPSTR(ROUTE_UPDATE), HTTP_POST, [&]() { - char json_buf[16]; - bool should_reboot = !Update.hasError() && !ota.invalidMd5; - Update.clearError(); - - sprintf_P(json_buf, JSON_UPDATE_FMT, should_reboot ? 1 : 0); - - server.send(200, FPSTR(CONTENT_TYPE_JSON), json_buf); - - if (should_reboot) - restartTimer.once(1, restart); - }, [&]() { - HTTPUpload& upload = server.upload(); - - if (upload.status == UPLOAD_FILE_START) { - ota.clean(); - - String s; - if (!getInputParam("md5", 0, s)) { - ota.invalidMd5 = true; - PRINTLN("http/ota: md5 not found"); - return; - } - - if (!Update.setMD5(s.c_str())) { - ota.invalidMd5 = true; - PRINTLN("http/ota: setMD5() failed"); - return; - } - - Serial.printf("http/ota: starting, filename=%s\n", upload.filename.c_str()); - if (!Update.begin(otaGetMaxUpdateSize())) { -#ifdef DEBUG - Update.printError(Serial); -#endif - } - } else if (upload.status == UPLOAD_FILE_WRITE) { - if (!Update.isRunning()) - return; - - PRINTF("http/ota: writing %ul\n", upload.currentSize); - esp_led.blink(1, 1); - if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { -#ifdef DEBUG - Update.printError(Serial); -#endif - } - } else if (upload.status == UPLOAD_FILE_END) { - if (!Update.isRunning()) - return; - - if (Update.end(true)) { - PRINTF("http/ota: ok, total size %ul\n", upload.totalSize); - } else { -#ifdef DEBUG - Update.printError(Serial); -#endif - } - } - }); - - server.onNotFound([&]() { - server.send(404, FPSTR(CONTENT_TYPE_HTML), NOT_FOUND); - }); - - server.begin(); -} - -void HttpServer::loop() { - server.handleClient(); -} - -void HttpServer::sendGzip(const StaticFile& file, PGM_P content_type) { - server.sendHeader(FPSTR(CONTENT_ENCODING), FPSTR(GZIP)); - server.send_P(200, content_type, (const char*)file.content, file.size); -} - -void HttpServer::sendError(const String& message) { - char buf[32]; - if (snprintf_P(buf, 32, PSTR("error: %s"), message.c_str()) == 32) - buf[31] = '\0'; - server.send(400, FPSTR(CONTENT_TYPE_HTML), buf); -} - -bool HttpServer::getInputParam(const char *field_name, - size_t max_len, - String& dst) { - if (!server.hasArg(field_name)) { - sendError(String(field_name) + String(MSG_IS_MISSING)); - return false; - } - - String field = server.arg(field_name); - if (!field.length() || (max_len != 0 && field.length() > max_len)) { - sendError(String(field_name) + String(MSG_IS_INVALID)); - return false; - } - - dst = field; - return true; -} - -}
\ No newline at end of file diff --git a/platformio/relayctl/src/led.cpp b/platformio/relayctl/src/led.cpp deleted file mode 100644 index b6b0d81..0000000 --- a/platformio/relayctl/src/led.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "led.h" -#include "config.def.h" - -namespace homekit { - -Led board_led(BOARD_LED_PIN); -Led esp_led(ESP_LED_PIN); - -}
\ No newline at end of file diff --git a/platformio/relayctl/src/led.h b/platformio/relayctl/src/led.h deleted file mode 100644 index 315523a..0000000 --- a/platformio/relayctl/src/led.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include <Arduino.h> - -namespace homekit { - -class Led { -private: - uint8_t _pin; - -public: - explicit Led(uint8_t pin) : _pin(pin) { - pinMode(_pin, OUTPUT); - off(); - } - - inline void off() const { digitalWrite(_pin, HIGH); } - inline void on() const { digitalWrite(_pin, LOW); } - - void on_off(uint16_t delay_ms, bool last_delay = false) const { - on(); - delay(delay_ms); - - off(); - if (last_delay) - delay(delay_ms); - } - - void blink(uint8_t count, uint16_t delay_ms) const { - for (uint8_t i = 0; i < count; i++) { - on_off(delay_ms, i < count-1); - } - } -}; - -extern Led board_led; -extern Led esp_led; - -}
\ No newline at end of file diff --git a/platformio/relayctl/src/leds.cpp b/platformio/relayctl/src/leds.cpp new file mode 100644 index 0000000..f0c9d51 --- /dev/null +++ b/platformio/relayctl/src/leds.cpp @@ -0,0 +1,11 @@ +#include "leds.h" + +namespace homekit { + +#ifdef CONFIG_TARGET_NODEMCU +Led* board_led = new Led(CONFIG_BOARD_LED_GPIO); +#endif +Led* mcu_led = new Led(CONFIG_MCU_LED_GPIO); + +} + diff --git a/platformio/relayctl/src/leds.h b/platformio/relayctl/src/leds.h new file mode 100644 index 0000000..04c1f79 --- /dev/null +++ b/platformio/relayctl/src/leds.h @@ -0,0 +1,15 @@ +#ifndef HOMEKIT_TEMPHUM_LEDS_H +#define HOMEKIT_TEMPHUM_LEDS_H + +#include <homekit/led.h> + +namespace homekit { + +#ifdef CONFIG_TARGET_NODEMCU +extern Led* board_led; +#endif +extern Led* mcu_led; + +} + +#endif //HOMEKIT_TEMPHUM_LEDS_H
\ No newline at end of file diff --git a/platformio/relayctl/src/logging.h b/platformio/relayctl/src/logging.h deleted file mode 100644 index 070f367..0000000 --- a/platformio/relayctl/src/logging.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include <stdlib.h> -#include "config.def.h" - -#ifdef DEBUG - -#define PRINTLN(s) Serial.println(s) -#define PRINT(s) Serial.print(s) -#define PRINTF(fmt, ...) Serial.printf(fmt, ##__VA_ARGS__) - -#else - -#define PRINTLN(s) -#define PRINT(s) -#define PRINTF(...) - -#endif diff --git a/platformio/relayctl/src/main.cpp b/platformio/relayctl/src/main.cpp index 3dab38b..13b00b3 100644 --- a/platformio/relayctl/src/main.cpp +++ b/platformio/relayctl/src/main.cpp @@ -3,15 +3,15 @@ #include <DNSServer.h> #include <Ticker.h> -#include "mqtt.h" -#include "config.h" -#include "logging.h" -#include "http_server.h" -#include "led.h" -#include "config.def.h" -#include "wifi.h" +#include <homekit/config.h> +#include <homekit/logging.h> +#include <homekit/http_server.h> +#include <homekit/wifi.h> +#include <homekit/stopwatch.h> + #include "relay.h" -#include "stopwatch.h" +#include "leds.h" +#include "mqtt.h" using namespace homekit; @@ -60,7 +60,7 @@ static void wifiConnect() { } static void wifiHotspot() { - esp_led.on(); + mcu_led->on(); auto scanResults = wifi::scan(); @@ -83,10 +83,10 @@ void setup() { relay::init(); - pinMode(FLASH_BUTTON_PIN, INPUT_PULLUP); + pinMode(CONFIG_FLASH_GPIO, INPUT_PULLUP); for (uint16_t i = 0; i < recovery_boot_detection_ms; i += recovery_boot_delay_ms) { delay(recovery_boot_delay_ms); - if (digitalRead(FLASH_BUTTON_PIN) == LOW) { + if (digitalRead(CONFIG_FLASH_GPIO) == LOW) { working_mode = WorkingMode::RECOVERY; break; } @@ -96,7 +96,7 @@ void setup() { if (config::isDirty(cfg)) { PRINTLN("config is dirty, erasing..."); config::erase(cfg); - board_led.blink(10, 50); + board_led->blink(10, 50); } switch (working_mode) { @@ -116,13 +116,13 @@ void loop() { if (working_mode == WorkingMode::NORMAL) { if (wifi_state == WiFiConnectionState::WAITING) { PRINT("."); - esp_led.blink(2, 50); + mcu_led->blink(2, 50); delay(1000); return; } if (wifi_state == WiFiConnectionState::JUST_CONNECTED) { - board_led.blink(3, 300); + board_led->blink(3, 300); wifi_state = WiFiConnectionState::CONNECTED; if (service == nullptr) @@ -147,7 +147,7 @@ void loop() { #if MQTT_BLINK // periodically blink board led if (blinkStopWatch.elapsed(5000)) { - board_led.blink(1, 10); + board_led->blink(1, 10); blinkStopWatch.save(); } #endif diff --git a/platformio/relayctl/src/mqtt.cpp b/platformio/relayctl/src/mqtt.cpp index 0314c75..ad3caef 100644 --- a/platformio/relayctl/src/mqtt.cpp +++ b/platformio/relayctl/src/mqtt.cpp @@ -1,24 +1,16 @@ #include <ESP8266httpUpdate.h> -#include "mqtt.h" -#include "logging.h" -#include "wifi.h" -#include "config.def.h" + +#include <homekit/logging.h> +#include <homekit/wifi.h> +#include <homekit/util.h> +#include <homekit/mqtt.h> + #include "relay.h" -#include "config.h" -#include "static.h" -#include "util.h" -#include "led.h" +#include "mqtt.h" +#include "leds.h" namespace homekit::mqtt { -static const uint8_t MQTT_CA_FINGERPRINT[] = DEFAULT_MQTT_CA_FINGERPRINT; -static const char MQTT_SERVER[] = DEFAULT_MQTT_SERVER; -static const uint16_t MQTT_PORT = DEFAULT_MQTT_PORT; -static const char MQTT_USERNAME[] = DEFAULT_MQTT_USERNAME; -static const char MQTT_PASSWORD[] = DEFAULT_MQTT_PASSWORD; -static const char MQTT_CLIENT_ID[] = DEFAULT_MQTT_CLIENT_ID; -static const char MQTT_SECRET[HOME_SECRET_SIZE+1] = HOME_SECRET; - static const char TOPIC_DIAGNOSTICS[] = "stat"; static const char TOPIC_INITIAL_DIAGNOSTICS[] = "stat1"; static const char TOPIC_OTA_RESPONSE[] = "otares"; @@ -38,7 +30,7 @@ using namespace espMqttClientTypes; MQTT::MQTT() { auto cfg = config::read(); - homeId = String(cfg.flags.node_configured ? cfg.home_id : wifi::HOME_ID); + homeId = String(cfg.flags.node_configured ? cfg.node_id : wifi::NODE_ID); randomSeed(micros()); @@ -178,7 +170,7 @@ void MQTT::sendInitialDiagnostics() { auto cfg = config::read(); InitialDiagnosticsPayload stat{ .ip = wifi::getIPAsInteger(), - .fw_version = FW_VERSION, + .fw_version = CONFIG_FW_VERSION, .rssi = wifi::getRSSI(), .free_heap = ESP.getFreeHeap(), .flags = DiagnosticsFlags{ @@ -252,19 +244,19 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size Update.runAsync(true); if (index == 0) { - if (length < HOME_SECRET_SIZE + MD5_SIZE) { + if (length < CONFIG_NODE_SECRET_SIZE + MD5_SIZE) { PRINTLN("mqtt/ota: failed to check secret, first packet size is too small"); return; } - if (memcmp((const char*)payload, HOME_SECRET, HOME_SECRET_SIZE) != 0) { + if (memcmp((const char*)payload, CONFIG_NODE_SECRET, CONFIG_NODE_SECRET_SIZE) != 0) { PRINTLN("mqtt/ota: invalid secret"); return; } - PRINTF("mqtt/ota: starting update, total=%ul\n", total-HOME_SECRET_SIZE); + PRINTF("mqtt/ota: starting update, total=%ul\n", total-NODE_SECRET_SIZE); for (int i = 0; i < MD5_SIZE; i++) { - md5Ptr += sprintf(md5Ptr, "%02x", *((unsigned char*)(payload+HOME_SECRET_SIZE+i))); + md5Ptr += sprintf(md5Ptr, "%02x", *((unsigned char*)(payload+CONFIG_NODE_SECRET_SIZE+i))); } md5[32] = '\0'; PRINTF("mqtt/ota: md5 is %s\n", md5); @@ -284,7 +276,7 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size ota.dataPacketId = packetId; - if (!Update.begin(total - HOME_SECRET_SIZE - MD5_SIZE)) { + if (!Update.begin(total - CONFIG_NODE_SECRET_SIZE - MD5_SIZE)) { ota.clean(); #ifdef DEBUG Update.printError(Serial); @@ -292,10 +284,10 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size sendOtaResponse(OTAResult::UPDATE_ERROR, Update.getError()); } - ota.written = Update.write(const_cast<uint8_t*>(payload)+HOME_SECRET_SIZE + MD5_SIZE, length-HOME_SECRET_SIZE - MD5_SIZE); - ota.written += HOME_SECRET_SIZE + MD5_SIZE; + ota.written = Update.write(const_cast<uint8_t*>(payload)+CONFIG_NODE_SECRET_SIZE + MD5_SIZE, length-CONFIG_NODE_SECRET_SIZE - MD5_SIZE); + ota.written += CONFIG_NODE_SECRET_SIZE + MD5_SIZE; - esp_led.blink(1, 1); + mcu_led->blink(1, 1); PRINTF("mqtt/ota: updating %u/%u\n", ota.written, Update.size()); } else { @@ -317,9 +309,9 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size } ota.written += length; - esp_led.blink(1, 1); + mcu_led->blink(1, 1); PRINTF("mqtt/ota: updating %u/%u\n", - ota.written - HOME_SECRET_SIZE - MD5_SIZE, + ota.written - CONFIG_NODE_SECRET_SIZE - MD5_SIZE, Update.size()); } else { PRINTF("mqtt/ota: position is invalid, expected %ul, got %ul\n", ota.written, index); diff --git a/platformio/relayctl/src/mqtt.h b/platformio/relayctl/src/mqtt.h index 2afb2e0..74d637a 100644 --- a/platformio/relayctl/src/mqtt.h +++ b/platformio/relayctl/src/mqtt.h @@ -1,9 +1,13 @@ +#ifndef HOMEKIT_RELAYCTL_MQTT_H +#define HOMEKIT_RELAYCTL_MQTT_H + #include <ESP8266WiFi.h> #include <espMqttClient.h> #include <Ticker.h> -#include "stopwatch.h" -namespace homekit { namespace mqtt { +#include <homekit/stopwatch.h> + +namespace homekit::mqtt { enum class OTAResult: uint8_t { OK = 0, @@ -98,4 +102,6 @@ struct OTAResponse { uint8_t error_code; } __attribute__((packed)); -} }
\ No newline at end of file +} + +#endif //HOMEKIT_RELAYCTL_MQTT_H
\ No newline at end of file diff --git a/platformio/relayctl/src/relay.h b/platformio/relayctl/src/relay.h index ba7f5a6..5287f09 100644 --- a/platformio/relayctl/src/relay.h +++ b/platformio/relayctl/src/relay.h @@ -1,24 +1,26 @@ -#pragma once +#ifndef HOMEKIT_RELAYCTL_RELAY_H +#define HOMEKIT_RELAYCTL_RELAY_H #include <Arduino.h> -#include "config.def.h" -namespace homekit { namespace relay { +namespace homekit::relay { inline void init() { - pinMode(RELAY_PIN, OUTPUT); + pinMode(CONFIG_RELAY_GPIO, OUTPUT); } inline bool getState() { - return digitalRead(RELAY_PIN) == HIGH; + return digitalRead(CONFIG_RELAY_GPIO) == HIGH; } inline void setOn() { - digitalWrite(RELAY_PIN, HIGH); + digitalWrite(CONFIG_RELAY_GPIO, HIGH); } inline void setOff() { - digitalWrite(RELAY_PIN, LOW); + digitalWrite(CONFIG_RELAY_GPIO, LOW); } -} }
\ No newline at end of file +} + +#endif //HOMEKIT_RELAYCTL_RELAY_H
\ No newline at end of file diff --git a/platformio/relayctl/src/static.cpp b/platformio/relayctl/src/static.cpp deleted file mode 100644 index 0e60044..0000000 --- a/platformio/relayctl/src/static.cpp +++ /dev/null @@ -1,450 +0,0 @@ -/** - * This file is autogenerated with make_static.sh script - */ - -#include "static.h" - -namespace homekit::files { - -static const uint8_t index_html_content[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x9d, 0x56, 0x4d, 0x8f, 0xdb, 0x36, - 0x10, 0xbd, 0xef, 0xaf, 0x60, 0x78, 0x28, 0x76, 0x81, 0xb5, 0xd4, 0xdd, 0xa0, 0x46, 0xd0, 0x48, - 0x02, 0x82, 0x34, 0x45, 0x02, 0xe4, 0xb0, 0x58, 0x23, 0x28, 0xd0, 0x8b, 0x41, 0x51, 0x23, 0x8b, - 0x35, 0x45, 0xb2, 0xe2, 0x48, 0x5e, 0xe7, 0xd7, 0x77, 0x48, 0x49, 0xfe, 0xd8, 0x1a, 0x9b, 0x8f, - 0x8b, 0xa5, 0x19, 0xce, 0xbc, 0x79, 0xf3, 0x38, 0x14, 0x9d, 0xbd, 0xaa, 0xac, 0xc4, 0xbd, 0x03, - 0xd6, 0x60, 0xab, 0x8b, 0xab, 0x2c, 0x3c, 0x98, 0x16, 0x66, 0x93, 0x73, 0x30, 0x3c, 0x38, 0x40, - 0x54, 0xf4, 0x68, 0x01, 0x05, 0xc5, 0xa0, 0x5b, 0xc0, 0xbf, 0xbd, 0x1a, 0x72, 0x2e, 0xad, 0x41, - 0x30, 0xb8, 0x08, 0xc9, 0x9c, 0x4d, 0x56, 0xce, 0x11, 0x9e, 0x30, 0x0d, 0x20, 0x6f, 0x99, 0x6c, - 0x44, 0xe7, 0x01, 0xf3, 0x1e, 0xeb, 0xc5, 0x1b, 0x3e, 0x63, 0x18, 0xd1, 0x42, 0xce, 0x07, 0x05, - 0x3b, 0x67, 0x3b, 0x3c, 0xc9, 0xdc, 0xa9, 0x0a, 0x9b, 0xbc, 0x82, 0x41, 0x49, 0x58, 0x44, 0xe3, - 0x56, 0x19, 0x85, 0x4a, 0xe8, 0x85, 0x97, 0x42, 0x43, 0x7e, 0x77, 0xdb, 0x92, 0xa3, 0xed, 0xdb, - 0xa3, 0x2d, 0x9e, 0xce, 0xec, 0xde, 0x43, 0x17, 0x0d, 0x51, 0x92, 0x6d, 0x6c, 0x28, 0x8a, 0x0a, - 0x35, 0x14, 0xef, 0xad, 0xa9, 0xd5, 0xa6, 0xef, 0x04, 0x2a, 0x6b, 0xb2, 0x74, 0x74, 0x5e, 0x65, - 0x5a, 0x99, 0x2d, 0xeb, 0x40, 0xe7, 0xdc, 0x37, 0xc4, 0x46, 0xf6, 0xc8, 0x14, 0x11, 0xe2, 0xac, - 0xe9, 0xa0, 0xce, 0x79, 0x5a, 0x8b, 0x21, 0xd8, 0x09, 0xfd, 0x70, 0x16, 0x3a, 0xcd, 0xb9, 0x6a, - 0xc5, 0x06, 0xd2, 0xa7, 0x45, 0x8c, 0x3b, 0x87, 0xc0, 0xbd, 0x06, 0xdf, 0x00, 0xe0, 0x1c, 0x1b, - 0xc5, 0x90, 0xde, 0x1f, 0xf0, 0x62, 0x48, 0x12, 0x3c, 0x94, 0xe9, 0x65, 0xa7, 0x1c, 0x32, 0xdf, - 0x49, 0x5a, 0x69, 0xab, 0xdf, 0x92, 0x7f, 0xc8, 0x9d, 0xa5, 0xa3, 0xfb, 0xf9, 0xba, 0x70, 0xee, - 0xf9, 0x7a, 0x3a, 0x6d, 0x4d, 0x69, 0xab, 0x3d, 0xb3, 0x46, 0x5b, 0x51, 0x11, 0x3d, 0x92, 0xec, - 0x9d, 0x73, 0xd7, 0x37, 0xa1, 0x42, 0xa5, 0x06, 0x26, 0xb5, 0xf0, 0x9e, 0xa8, 0x84, 0x8e, 0x79, - 0xb1, 0x02, 0x44, 0x65, 0x36, 0x9e, 0x65, 0xde, 0x09, 0xc3, 0x14, 0x65, 0x84, 0x3c, 0x72, 0xad, - 0x49, 0x34, 0xd0, 0xbc, 0xb8, 0x9e, 0xec, 0x24, 0x49, 0x6e, 0xa8, 0x18, 0x45, 0x51, 0x4d, 0x02, - 0x3a, 0x87, 0x2b, 0xb5, 0x95, 0xdb, 0x50, 0xa2, 0xb6, 0x5d, 0xcb, 0x68, 0x63, 0x1b, 0x4b, 0x50, - 0xce, 0x7a, 0xea, 0x5d, 0xc8, 0x20, 0x72, 0xec, 0x56, 0x60, 0x4f, 0xcd, 0x8f, 0x5b, 0x6e, 0x00, - 0x77, 0xb6, 0xdb, 0xae, 0xfd, 0x44, 0xe1, 0x19, 0xc1, 0x00, 0x34, 0x73, 0xf8, 0x4b, 0xfd, 0xa9, - 0xd8, 0x6a, 0xf5, 0xe9, 0x8f, 0x0b, 0x95, 0x63, 0x9c, 0x32, 0xae, 0xc7, 0xa8, 0x21, 0x68, 0x90, - 0x18, 0xfb, 0xf0, 0x5e, 0x55, 0xeb, 0xd1, 0x9e, 0x4b, 0x06, 0x17, 0x3f, 0x24, 0xf6, 0x5a, 0x8f, - 0x73, 0x15, 0x12, 0xad, 0x0b, 0x24, 0xd9, 0x20, 0x74, 0x4f, 0x81, 0xbc, 0xf8, 0x7c, 0xe8, 0x3a, - 0x4b, 0xc7, 0xb5, 0xa0, 0xf0, 0x08, 0x17, 0xde, 0x2e, 0xf3, 0x38, 0xe5, 0xfb, 0x40, 0x6e, 0x6a, - 0xb0, 0xfa, 0x26, 0xe7, 0xf8, 0x32, 0x4d, 0x88, 0x9b, 0x92, 0xf8, 0x81, 0xc9, 0x44, 0xdd, 0xf9, - 0xed, 0x25, 0xe6, 0xb1, 0xd3, 0x5a, 0x57, 0xeb, 0xb8, 0x4e, 0xf3, 0xaf, 0xc1, 0x6c, 0xe8, 0xd8, - 0xf0, 0xe5, 0x6b, 0xce, 0x2a, 0xe5, 0xc3, 0xe0, 0x57, 0x17, 0x8a, 0xfb, 0xbe, 0x9c, 0xb8, 0xd2, - 0xc4, 0x86, 0x17, 0x46, 0xee, 0x38, 0xf5, 0xbb, 0x08, 0x55, 0x9c, 0xb1, 0x92, 0x0d, 0xc8, 0x6d, - 0x69, 0x9f, 0x0e, 0x3a, 0xce, 0x61, 0xa3, 0xd0, 0x87, 0x24, 0x16, 0x5e, 0x99, 0x3b, 0x34, 0x1e, - 0x91, 0x8f, 0x6a, 0xbd, 0x2c, 0xda, 0x47, 0xdb, 0x02, 0xfb, 0x8e, 0x2d, 0x3e, 0x25, 0x16, 0x0e, - 0xd4, 0x89, 0x54, 0x27, 0xfd, 0xdf, 0x2d, 0x67, 0xb2, 0x4d, 0xd8, 0xf3, 0x59, 0xa6, 0xe6, 0xf2, - 0x00, 0x9c, 0x4a, 0x35, 0xd5, 0x2f, 0x7b, 0x44, 0x1a, 0x88, 0xb1, 0x0e, 0xc9, 0xd5, 0x2a, 0x3c, - 0x86, 0xcd, 0x3a, 0x8c, 0xee, 0x62, 0x25, 0x06, 0x60, 0xc2, 0x54, 0xec, 0x11, 0x4a, 0x6b, 0x31, - 0x4b, 0xc7, 0xe4, 0x00, 0x16, 0xb8, 0x5f, 0x6c, 0x7d, 0x3a, 0x80, 0x5f, 0x5c, 0x25, 0x10, 0x58, - 0xad, 0xba, 0x76, 0x27, 0x3a, 0x60, 0xd7, 0x49, 0xa9, 0xcc, 0xcd, 0xcf, 0x9e, 0xb0, 0x3e, 0xa2, - 0x71, 0x06, 0x46, 0x8e, 0xc4, 0xdb, 0x5e, 0xa3, 0x72, 0xa2, 0xc3, 0x48, 0x64, 0x41, 0xab, 0x62, - 0xd6, 0x65, 0x8c, 0x7d, 0xf1, 0xf8, 0x5d, 0xd4, 0xbc, 0x56, 0xc4, 0x9b, 0x4a, 0x4a, 0x70, 0xf4, - 0x95, 0x0e, 0x74, 0x6f, 0xc3, 0x4f, 0xb2, 0xf9, 0x3a, 0x23, 0xc7, 0x88, 0x6f, 0x28, 0x79, 0x26, - 0xe0, 0x51, 0xfe, 0x2f, 0x2e, 0x7c, 0x6e, 0x7e, 0x44, 0xc0, 0x47, 0xa0, 0x0e, 0xd8, 0xdc, 0xc5, - 0xcf, 0x0a, 0xd7, 0x05, 0x14, 0xfe, 0x7d, 0x64, 0x27, 0x5c, 0xe5, 0xd7, 0x53, 0x56, 0xa4, 0xf0, - 0x23, 0x9c, 0x3f, 0x99, 0xda, 0xbe, 0xc0, 0xf4, 0xc3, 0xea, 0xe1, 0xcd, 0xfd, 0x72, 0xb9, 0x28, - 0x85, 0xa7, 0x51, 0xcb, 0xca, 0x82, 0xae, 0x13, 0xb1, 0x97, 0xa8, 0xa9, 0x46, 0x71, 0x7b, 0x9c, - 0x95, 0x61, 0x99, 0x95, 0x5d, 0x71, 0xf5, 0x40, 0xdb, 0xcb, 0x6c, 0xcd, 0x32, 0x31, 0x5d, 0x2b, - 0xe1, 0x5a, 0xf6, 0xbf, 0xa7, 0xe9, 0x46, 0x61, 0x22, 0x9b, 0x3b, 0x97, 0x28, 0x9b, 0x36, 0x74, - 0xba, 0xb6, 0x64, 0x93, 0x2f, 0xe5, 0xc5, 0x64, 0x65, 0xa9, 0x28, 0x58, 0xb9, 0xff, 0x7f, 0xe6, - 0x94, 0xc5, 0x8b, 0x0f, 0xc3, 0x06, 0xcc, 0x9e, 0xfd, 0xad, 0x8c, 0xa5, 0x2b, 0x7a, 0x88, 0x09, - 0xbf, 0x48, 0xeb, 0xf6, 0x6f, 0xd9, 0xfd, 0xaf, 0xf7, 0xf7, 0xc7, 0xa3, 0x1d, 0x2e, 0x9d, 0x78, - 0x07, 0xc5, 0xbf, 0x0d, 0xff, 0x01, 0x5f, 0x1c, 0x62, 0xab, 0x47, 0x08, 0x00, 0x00, -}; -const StaticFile index_html PROGMEM = {(sizeof(index_html_content)/sizeof(index_html_content[0])), index_html_content}; - -static const uint8_t app_js_content[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x9d, 0x57, 0x6d, 0x6f, 0xdb, 0x46, - 0x12, 0xfe, 0xde, 0x5f, 0x41, 0x2d, 0x70, 0x06, 0xf7, 0x44, 0xd3, 0x2f, 0xd7, 0x02, 0x85, 0x18, - 0x42, 0x48, 0xda, 0xe4, 0x92, 0x22, 0xa9, 0x8b, 0x24, 0x57, 0x1c, 0x60, 0xf8, 0x82, 0x95, 0x38, - 0xb2, 0x18, 0x53, 0xbb, 0xec, 0xee, 0xd2, 0xb2, 0x4f, 0x11, 0x70, 0x69, 0x0a, 0xb4, 0x40, 0x0b, - 0x04, 0xe8, 0xf7, 0xcb, 0xa7, 0xfe, 0x00, 0x37, 0x77, 0xbe, 0x4b, 0x2e, 0x4d, 0xfa, 0x17, 0xa8, - 0x7f, 0xd4, 0x99, 0x25, 0x29, 0xd1, 0xb2, 0x81, 0x06, 0xf7, 0xc1, 0x12, 0xb5, 0x9c, 0x9d, 0x9d, - 0x79, 0x66, 0x9e, 0x67, 0xc7, 0xa3, 0x42, 0x0e, 0x6d, 0xaa, 0xa4, 0x07, 0x3e, 0xf0, 0x99, 0x06, - 0x5b, 0x68, 0xc9, 0xf6, 0xd5, 0xe0, 0x31, 0x0c, 0xad, 0xb7, 0xe7, 0xbe, 0x0e, 0x58, 0x1c, 0xc7, - 0xd5, 0x63, 0x98, 0x6b, 0x65, 0x95, 0x3d, 0xcd, 0x21, 0xb4, 0xea, 0x81, 0xd5, 0xa9, 0x3c, 0x0c, - 0x87, 0x22, 0xcb, 0x70, 0xef, 0x7c, 0xd4, 0x78, 0xb2, 0x2b, 0x4f, 0x5e, 0xa2, 0x86, 0xc5, 0x04, - 0xa4, 0x0d, 0x0f, 0xc1, 0xde, 0xcc, 0x80, 0x1e, 0x6f, 0x9c, 0xde, 0x49, 0x2e, 0xd8, 0x4b, 0xb2, - 0x87, 0xd0, 0xd8, 0xd3, 0x0c, 0xc2, 0x24, 0x35, 0x79, 0x26, 0x4e, 0x63, 0x26, 0x95, 0x04, 0xb6, - 0x32, 0xd2, 0x2d, 0xa7, 0x80, 0x61, 0xc0, 0x31, 0xba, 0xfa, 0x14, 0x46, 0xa2, 0xc8, 0xec, 0xc6, - 0xc6, 0xfa, 0x8a, 0xcf, 0x03, 0x72, 0xa8, 0xf2, 0x2f, 0xb4, 0xca, 0xc5, 0xa1, 0x20, 0x17, 0x64, - 0xb5, 0xb6, 0xe4, 0xcc, 0x86, 0x42, 0x0e, 0x21, 0xbb, 0x51, 0x0c, 0x06, 0x19, 0xc4, 0x9d, 0x6d, - 0x5c, 0xa9, 0x8e, 0xf9, 0x52, 0x64, 0x05, 0x2e, 0xec, 0x04, 0x9d, 0x9d, 0x55, 0x18, 0x69, 0x3b, - 0x0c, 0x2f, 0x95, 0xc6, 0xd2, 0x6e, 0x35, 0xf2, 0x6e, 0x6a, 0xad, 0x74, 0x1f, 0xc2, 0x09, 0x18, - 0x23, 0x0e, 0xa1, 0x07, 0x5d, 0xd6, 0x8a, 0x5e, 0xd5, 0x29, 0x82, 0xbd, 0x6e, 0x11, 0xb5, 0x41, - 0x61, 0xc1, 0x67, 0x98, 0xaa, 0xc0, 0x33, 0x13, 0x16, 0xac, 0x1e, 0x5b, 0xb0, 0x88, 0x6a, 0x8f, - 0x86, 0x89, 0x3a, 0x86, 0xab, 0xb6, 0xb5, 0x6c, 0x8d, 0xcf, 0x67, 0xa3, 0x56, 0x25, 0x03, 0xcb, - 0x67, 0xb2, 0xc8, 0xb2, 0x4e, 0x1c, 0x23, 0x3a, 0x3e, 0x84, 0xc7, 0x2e, 0x19, 0xcb, 0x03, 0xf2, - 0x3a, 0x3f, 0x16, 0xda, 0x33, 0xf1, 0x76, 0xb4, 0xdc, 0x52, 0xe0, 0xfe, 0x5d, 0xac, 0x72, 0xb7, - 0x6b, 0x36, 0x36, 0xa4, 0x6f, 0x7d, 0x96, 0x29, 0x91, 0x60, 0x75, 0x1f, 0x65, 0x62, 0x00, 0x19, - 0xe3, 0xd5, 0x9e, 0x24, 0x5e, 0xd6, 0x73, 0xa4, 0xf4, 0xc4, 0x84, 0x12, 0xec, 0x54, 0xe9, 0xa3, - 0x47, 0x98, 0x98, 0x45, 0x6b, 0x13, 0x25, 0xa1, 0x48, 0x92, 0x9b, 0x54, 0x89, 0xbb, 0xa9, 0xb1, - 0x20, 0x41, 0xfb, 0xcc, 0x14, 0x83, 0x49, 0x6a, 0x59, 0xe0, 0x37, 0xc7, 0xb5, 0xfb, 0x23, 0x1c, - 0xa7, 0x49, 0x15, 0x5d, 0x88, 0x19, 0x4e, 0x7c, 0xde, 0x4f, 0xc2, 0xdc, 0x1c, 0xd5, 0x4b, 0x19, - 0xc8, 0x43, 0x3b, 0xbe, 0xf6, 0x71, 0xdf, 0x17, 0x19, 0x68, 0x0c, 0xab, 0xfc, 0x67, 0x79, 0x5e, - 0xbe, 0x2c, 0xcf, 0x17, 0xff, 0x28, 0xdf, 0x2e, 0xbe, 0x2f, 0x5f, 0x7b, 0xe5, 0xaf, 0xe5, 0x19, - 0xfe, 0x78, 0x57, 0xbe, 0x59, 0xfc, 0xe0, 0xf9, 0xe5, 0x2f, 0xe5, 0xab, 0xf2, 0x2d, 0xfe, 0xfd, - 0x52, 0x9e, 0xd1, 0x0a, 0x3e, 0x9f, 0x2d, 0x9e, 0x7b, 0xe5, 0xbf, 0xcb, 0x37, 0xee, 0xc5, 0x99, - 0xb7, 0xe9, 0x7d, 0xec, 0x2d, 0x9e, 0x3a, 0x8b, 0x97, 0xb4, 0x0b, 0xff, 0x5e, 0x72, 0xc6, 0x03, - 0xea, 0x2f, 0xde, 0xdb, 0xdc, 0x41, 0x10, 0x92, 0xd0, 0x18, 0x0c, 0xca, 0x40, 0x86, 0x1d, 0x0f, - 0xc9, 0x1d, 0x99, 0xc0, 0xc9, 0x85, 0x00, 0xbc, 0xf2, 0x25, 0x9e, 0xfd, 0x33, 0x1e, 0x7b, 0xe6, - 0x7c, 0x2e, 0xbe, 0x2e, 0xdf, 0x2d, 0xbe, 0x2d, 0xff, 0x87, 0x8f, 0x78, 0xd2, 0xbb, 0xc5, 0xd3, - 0xc5, 0xd7, 0x8b, 0x67, 0x14, 0xd8, 0xd2, 0xef, 0xb1, 0x4a, 0x13, 0x6c, 0x02, 0x74, 0xea, 0xb0, - 0xe0, 0xbd, 0xa5, 0xbb, 0x1f, 0x29, 0x1b, 0xdc, 0xf5, 0x0a, 0x9d, 0x9c, 0x7b, 0x63, 0x35, 0xc1, - 0xae, 0x4a, 0x9a, 0x7d, 0x73, 0xce, 0x03, 0xdc, 0x33, 0x56, 0xd3, 0x47, 0x84, 0xc9, 0x65, 0x68, - 0x87, 0x63, 0x21, 0x0f, 0x61, 0x0d, 0xda, 0x0a, 0xc0, 0x8b, 0xbd, 0x46, 0x94, 0x65, 0xd8, 0xda, - 0x56, 0x68, 0x64, 0x62, 0x38, 0x1c, 0xc3, 0xf0, 0x08, 0x92, 0x3e, 0xb3, 0x70, 0x62, 0x59, 0x8f, - 0xe5, 0xc2, 0x18, 0x2c, 0x24, 0xf5, 0x54, 0x75, 0x24, 0x01, 0xf0, 0x9e, 0xc7, 0x51, 0x63, 0xd8, - 0x78, 0xe9, 0xfa, 0x02, 0x6c, 0xd1, 0xe6, 0xce, 0xb2, 0x05, 0xeb, 0xf7, 0x2a, 0xa7, 0x8d, 0x66, - 0xdf, 0x1e, 0xe0, 0x6a, 0xab, 0xd6, 0x31, 0x63, 0x55, 0xc2, 0xe2, 0xb1, 0x38, 0x21, 0xb9, 0xf0, - 0xd9, 0x16, 0xb2, 0xcb, 0x16, 0x86, 0x05, 0xb3, 0x79, 0xeb, 0x48, 0x1b, 0x48, 0x3e, 0xb3, 0xfa, - 0x74, 0x96, 0x8e, 0x7c, 0xcb, 0xed, 0x58, 0xab, 0xa9, 0x67, 0x23, 0xf0, 0x5d, 0x2b, 0x05, 0x32, - 0x24, 0x0c, 0x1f, 0xa5, 0xc9, 0x93, 0x27, 0x44, 0x00, 0x24, 0x78, 0x75, 0x48, 0xb0, 0xfa, 0x55, - 0xd5, 0xa0, 0x5e, 0xc0, 0xce, 0x9f, 0x0f, 0x85, 0x1d, 0x8e, 0xd1, 0xd7, 0xac, 0x2a, 0x4a, 0x8a, - 0x8f, 0x7c, 0xbe, 0x1e, 0x0a, 0xca, 0xc4, 0x5a, 0x20, 0x8e, 0x65, 0x75, 0x20, 0x50, 0x07, 0x02, - 0x51, 0x0d, 0x5e, 0x2a, 0x11, 0xb1, 0xdb, 0x0f, 0xef, 0xdd, 0xc5, 0xbc, 0x22, 0x24, 0x8b, 0x4f, - 0x30, 0x49, 0xe4, 0x9c, 0xbc, 0x66, 0xc3, 0x0c, 0x11, 0xad, 0x7b, 0x3b, 0x92, 0xdd, 0x6e, 0x85, - 0xa1, 0x8e, 0xab, 0x17, 0xfb, 0xf2, 0x60, 0x7f, 0xfb, 0x20, 0x50, 0xad, 0x9f, 0x3b, 0x07, 0x8d, - 0x5b, 0x91, 0xe7, 0x20, 0x13, 0x5f, 0xc2, 0xd4, 0xdb, 0x73, 0x40, 0xfa, 0xba, 0xcb, 0x3c, 0x9f, - 0x75, 0x15, 0x7e, 0x25, 0x37, 0x26, 0x9c, 0x05, 0x1a, 0x83, 0x17, 0x7e, 0x65, 0xdf, 0xce, 0x0f, - 0x56, 0xf9, 0x41, 0x95, 0xdf, 0xfc, 0x02, 0xff, 0x29, 0x06, 0x58, 0x27, 0x78, 0x91, 0x27, 0xc2, - 0xc2, 0x8a, 0xdf, 0xf0, 0x5e, 0xfc, 0x46, 0x5c, 0x10, 0x13, 0x8d, 0xdf, 0x41, 0x07, 0xc2, 0x51, - 0x9a, 0x55, 0x1f, 0xa6, 0xce, 0x99, 0xd7, 0xe4, 0x6f, 0x38, 0xf0, 0x13, 0xf2, 0xe8, 0x75, 0xf9, - 0xc6, 0x43, 0x2e, 0xfe, 0x8c, 0x84, 0x42, 0x46, 0x22, 0x2f, 0xcf, 0x89, 0xc7, 0xc4, 0xdd, 0xb7, - 0x6b, 0x84, 0x43, 0x72, 0x74, 0x76, 0x22, 0x54, 0xd4, 0x86, 0x4c, 0x51, 0x05, 0x2d, 0x61, 0xf2, - 0xd7, 0x7b, 0x77, 0x6f, 0x5b, 0x9b, 0xdf, 0x87, 0xaf, 0x0a, 0x30, 0x36, 0x10, 0x6e, 0xf1, 0x16, - 0x66, 0xf2, 0xa9, 0xb0, 0x22, 0x6a, 0x8e, 0x6d, 0x50, 0x64, 0x14, 0x14, 0xb1, 0x62, 0x15, 0x21, - 0x22, 0xcf, 0xb1, 0x87, 0x8a, 0x9c, 0xf4, 0xef, 0x8a, 0x5c, 0xf1, 0xfe, 0x3b, 0xd4, 0x28, 0xf1, - 0x6b, 0xd9, 0xba, 0x08, 0x02, 0x1d, 0xaf, 0xb9, 0x0a, 0x4d, 0xfa, 0x77, 0x88, 0x24, 0x55, 0x12, - 0xdd, 0x41, 0x72, 0x4d, 0xf7, 0xef, 0x09, 0x3b, 0x0e, 0xb5, 0x2a, 0xf0, 0xf8, 0x66, 0x75, 0x4b, - 0xff, 0x71, 0x67, 0x7b, 0x9b, 0xe3, 0x8d, 0x7a, 0x2b, 0x3d, 0x81, 0xc4, 0xdf, 0xe5, 0x3d, 0xfc, - 0x1d, 0x34, 0xf9, 0xb5, 0x5a, 0x49, 0x76, 0xd9, 0x1f, 0x18, 0x35, 0xa6, 0x0c, 0x95, 0xd4, 0x20, - 0x92, 0x53, 0x62, 0x08, 0x54, 0xb4, 0x8c, 0x97, 0x01, 0x35, 0xb5, 0x64, 0xe5, 0x8b, 0x75, 0x40, - 0x09, 0xcb, 0xff, 0x22, 0x8a, 0x4e, 0x42, 0x17, 0xdf, 0xb9, 0xc5, 0x77, 0x81, 0xb7, 0x78, 0xe6, - 0x44, 0x8b, 0x74, 0xf4, 0x35, 0x3d, 0x91, 0x36, 0x92, 0xb4, 0x92, 0xce, 0x9e, 0xbb, 0x0d, 0xff, - 0x42, 0xf3, 0x67, 0xe5, 0x7f, 0xf0, 0xe9, 0x1c, 0x0d, 0x9f, 0x2e, 0x9e, 0xb3, 0x08, 0x4b, 0xfc, - 0x21, 0xca, 0xa5, 0x0c, 0x5d, 0x24, 0x0f, 0x28, 0x12, 0x4e, 0x74, 0x20, 0x0d, 0xfd, 0xec, 0xc1, - 0xde, 0xe7, 0x61, 0x2e, 0xb4, 0x01, 0x9f, 0xde, 0x9b, 0x1c, 0x29, 0x0f, 0x0f, 0x51, 0x6c, 0x38, - 0xfd, 0xc2, 0x1b, 0xba, 0x5f, 0x15, 0x1f, 0x78, 0xaf, 0xe9, 0x82, 0x17, 0x18, 0xce, 0x2b, 0x8c, - 0xd7, 0xc9, 0xe8, 0x15, 0x9d, 0xc0, 0x2e, 0x11, 0x15, 0x6f, 0xb2, 0xb9, 0x83, 0x02, 0xe8, 0xf2, - 0x8d, 0xdb, 0xa2, 0xd4, 0xee, 0x74, 0x32, 0xc1, 0x7a, 0xfb, 0xec, 0x8b, 0xbd, 0x07, 0x0f, 0x59, - 0x60, 0x1b, 0x25, 0x12, 0xce, 0x9a, 0xc0, 0x34, 0xd4, 0x0d, 0x82, 0xfa, 0x8a, 0xc0, 0xad, 0x8b, - 0xf8, 0x3e, 0xf2, 0x57, 0x35, 0xfa, 0xd2, 0xe3, 0x85, 0x26, 0x9f, 0xad, 0xda, 0xf2, 0x16, 0xae, - 0xdf, 0x47, 0x90, 0x40, 0x47, 0x14, 0x2e, 0x95, 0x7d, 0xbd, 0x5a, 0x36, 0x9e, 0xa6, 0x32, 0x51, - 0xd3, 0x70, 0x92, 0x7c, 0x54, 0x41, 0x86, 0x20, 0xf1, 0x68, 0x7d, 0x66, 0xa8, 0x62, 0xc6, 0x89, - 0x61, 0xab, 0x62, 0x66, 0x1f, 0xcd, 0x63, 0xd6, 0xad, 0x2e, 0xf6, 0x86, 0x10, 0x57, 0x82, 0xd2, - 0x60, 0x72, 0x11, 0xe8, 0xc5, 0xb7, 0x74, 0xef, 0xd4, 0x54, 0x5b, 0x7c, 0x53, 0x11, 0x91, 0x2e, - 0x2e, 0xf2, 0x41, 0x75, 0xbd, 0x6e, 0x6e, 0xa4, 0x52, 0xe8, 0xd3, 0x6a, 0xd8, 0x5b, 0x4b, 0x95, - 0xd8, 0xe2, 0x84, 0xa4, 0xd3, 0x3a, 0xa6, 0x35, 0x07, 0xa2, 0xc8, 0x06, 0x3a, 0x48, 0x2b, 0x35, - 0x88, 0x75, 0x25, 0xc9, 0x01, 0x6b, 0x2c, 0x58, 0x27, 0xa6, 0x7b, 0x09, 0xa7, 0xa7, 0xb4, 0x96, - 0x4f, 0x02, 0xcb, 0x4d, 0x52, 0x08, 0x36, 0x8e, 0x95, 0x03, 0x31, 0x3c, 0xf2, 0x26, 0x85, 0xb1, - 0xde, 0x00, 0x3c, 0xe1, 0x2d, 0xf7, 0x71, 0xea, 0xbd, 0x8e, 0xbc, 0xbc, 0x49, 0x2a, 0xaf, 0xd0, - 0x99, 0x67, 0x72, 0x18, 0xa6, 0xa3, 0x94, 0x66, 0xa4, 0xc8, 0x4c, 0xd3, 0xba, 0x69, 0x86, 0xc2, - 0x00, 0xfb, 0xf3, 0xcd, 0x87, 0xac, 0x47, 0x82, 0xed, 0xa3, 0x4e, 0x36, 0xba, 0xac, 0x70, 0x92, - 0xf3, 0x34, 0xd7, 0xe1, 0x58, 0x98, 0xbd, 0xa9, 0xa4, 0x09, 0x11, 0xa1, 0x3a, 0xf5, 0x15, 0xc7, - 0x3b, 0x4a, 0x76, 0x63, 0xdf, 0xcd, 0x05, 0x12, 0x99, 0x88, 0x77, 0xda, 0xde, 0xc8, 0x67, 0x7d, - 0xc6, 0xfb, 0xf8, 0xd1, 0x63, 0x1b, 0x8c, 0x77, 0x41, 0x0e, 0x55, 0x02, 0x7f, 0xb9, 0x7f, 0xe7, - 0x13, 0x35, 0xc1, 0x3e, 0xc7, 0x96, 0xc1, 0x8d, 0x5d, 0x86, 0x65, 0xb9, 0xe2, 0x8d, 0xde, 0x57, - 0x07, 0x9c, 0x47, 0x03, 0xc4, 0xf6, 0x28, 0x72, 0x11, 0xb9, 0xae, 0x5c, 0x86, 0xe4, 0x9a, 0x41, - 0xc4, 0xfb, 0x07, 0xd1, 0xfb, 0x04, 0x27, 0xc2, 0xbc, 0x30, 0x28, 0xed, 0xff, 0x47, 0x04, 0x3a, - 0x16, 0xe1, 0x63, 0x95, 0x22, 0x2d, 0x30, 0x87, 0x79, 0x3d, 0x12, 0x5e, 0xd6, 0xd0, 0x46, 0x34, - 0x4d, 0xc5, 0x21, 0xba, 0x7c, 0x83, 0x2a, 0xe4, 0xd8, 0x5d, 0xec, 0x86, 0x1a, 0xb4, 0xb6, 0xbd, - 0xed, 0x5a, 0xdc, 0x67, 0x9f, 0x28, 0x89, 0x8c, 0xb1, 0x9b, 0xd5, 0xd0, 0xc1, 0x50, 0x6d, 0xb3, - 0x74, 0xe8, 0x06, 0xee, 0xad, 0x93, 0xcd, 0xe9, 0x74, 0xba, 0x49, 0x77, 0xcb, 0x26, 0x16, 0xaa, - 0x8a, 0x8e, 0xc6, 0x1d, 0xf3, 0x3b, 0x82, 0x56, 0x6b, 0x8d, 0x69, 0x6b, 0x0d, 0x2d, 0xb2, 0x7a, - 0x44, 0x40, 0x88, 0x70, 0x72, 0xed, 0x6c, 0xfd, 0x6d, 0xf7, 0xc9, 0xce, 0xee, 0xee, 0x9f, 0xb6, - 0x42, 0x8b, 0xf1, 0xf8, 0x18, 0x9c, 0x7b, 0xcd, 0x2f, 0x77, 0xca, 0x18, 0x53, 0xf4, 0xe8, 0x74, - 0x8f, 0x75, 0x97, 0x66, 0x51, 0xea, 0xbb, 0x0e, 0x6d, 0xa9, 0x97, 0xb9, 0xa8, 0x5e, 0xa4, 0x38, - 0xe6, 0x4a, 0xc5, 0x41, 0xad, 0xa9, 0x46, 0x0a, 0x32, 0x70, 0x82, 0xe2, 0x7a, 0x8d, 0x50, 0xea, - 0xd3, 0x7a, 0x4f, 0x63, 0x96, 0xf3, 0x9a, 0xe4, 0x34, 0x58, 0xc4, 0x33, 0xe4, 0x51, 0xcf, 0x86, - 0x83, 0x94, 0xee, 0x82, 0xc0, 0x59, 0xf3, 0x20, 0x57, 0xa6, 0xbd, 0xe8, 0x90, 0xc6, 0x43, 0xf1, - 0x3f, 0x95, 0x7a, 0x6b, 0x2a, 0x53, 0x7b, 0x3d, 0xcf, 0xdb, 0xe0, 0xe0, 0xf4, 0xef, 0xee, 0xf9, - 0xe8, 0x83, 0xdf, 0x00, 0xbe, 0x18, 0xb5, 0xbd, 0xce, 0x0d, 0x00, 0x00, -}; -const StaticFile app_js PROGMEM = {(sizeof(app_js_content)/sizeof(app_js_content[0])), app_js_content}; - -static const uint8_t md5_js_content[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xad, 0x59, 0x79, 0x73, 0x1b, 0xb7, - 0x15, 0xff, 0xbf, 0x9f, 0x42, 0xe2, 0x4c, 0x39, 0xbb, 0xb3, 0x2b, 0x05, 0xf7, 0x61, 0x72, 0xe5, - 0x89, 0x93, 0x1e, 0xe9, 0x95, 0xb6, 0x69, 0xd2, 0x83, 0x43, 0xcd, 0xd0, 0xd2, 0xd2, 0xbb, 0x89, - 0x42, 0xaa, 0x58, 0xd0, 0xb2, 0x62, 0xd2, 0x9f, 0xbd, 0x0f, 0xd8, 0x0b, 0x4b, 0x89, 0x3a, 0xac, - 0x8e, 0x2d, 0x2c, 0x08, 0xbc, 0xf7, 0x80, 0xdf, 0xbb, 0x70, 0x1d, 0x2f, 0x37, 0xab, 0x0b, 0x5b, - 0xae, 0x57, 0x51, 0xfc, 0x71, 0xb4, 0xa9, 0xf2, 0xa3, 0xca, 0x9a, 0xf2, 0xc2, 0x8e, 0x26, 0xef, - 0x17, 0xe6, 0xc8, 0xa6, 0x26, 0x1b, 0x95, 0xab, 0xeb, 0x8d, 0x3d, 0x2a, 0xab, 0xa3, 0x72, 0xf5, - 0x7e, 0x71, 0x55, 0x5e, 0x1e, 0xd9, 0xdb, 0xeb, 0x7c, 0x94, 0x96, 0xd9, 0xfb, 0x35, 0xfc, 0x40, - 0xc7, 0x59, 0x76, 0x53, 0xae, 0x2e, 0xd7, 0x37, 0xa7, 0x5f, 0x1a, 0xb3, 0xb8, 0x7d, 0xb3, 0x59, - 0x2e, 0x73, 0x93, 0x16, 0xd9, 0x08, 0x61, 0x42, 0x19, 0x17, 0x52, 0xe9, 0xc5, 0xdb, 0x8b, 0xcb, - 0x7c, 0x39, 0x3a, 0xad, 0xae, 0xaf, 0x4a, 0x1b, 0x8d, 0x46, 0x71, 0x5a, 0x65, 0x33, 0x4c, 0x54, - 0x4a, 0x89, 0x14, 0x2a, 0x55, 0x54, 0x29, 0x81, 0x54, 0x7a, 0x42, 0x30, 0x93, 0x4c, 0x51, 0xc1, - 0xd4, 0x3c, 0xcd, 0xb3, 0x19, 0x4a, 0x55, 0x8a, 0x45, 0x4a, 0xd8, 0x3c, 0x5d, 0x64, 0xb3, 0x51, - 0x91, 0x7f, 0x18, 0xa5, 0xa3, 0x85, 0x1b, 0x04, 0xbe, 0x97, 0xe5, 0xbb, 0xbc, 0xb2, 0x50, 0x79, - 0xeb, 0x07, 0x6c, 0x7b, 0xde, 0xb4, 0xbf, 0xde, 0x2e, 0xaa, 0x5c, 0xb0, 0xd1, 0x3c, 0x5d, 0x66, - 0xa3, 0x2f, 0xdf, 0x7c, 0xf5, 0xf5, 0x6f, 0x7e, 0xfb, 0xbb, 0xdf, 0x7f, 0xf3, 0x87, 0x3f, 0xfe, - 0xe9, 0xcf, 0x7f, 0xf9, 0xf6, 0xaf, 0x7f, 0xfb, 0xfb, 0x77, 0xff, 0xf8, 0xfe, 0x87, 0x7f, 0xfe, - 0xeb, 0xdf, 0xff, 0xa9, 0x67, 0xf6, 0xae, 0x28, 0x7f, 0xfc, 0xe9, 0xea, 0xe7, 0xd5, 0xfa, 0xfa, - 0xbf, 0xa6, 0xb2, 0x9b, 0xf7, 0x37, 0x1f, 0x6e, 0x7f, 0xe9, 0x67, 0x9f, 0x7c, 0x11, 0xce, 0x7c, - 0x95, 0xcd, 0xe6, 0x93, 0x72, 0x19, 0x95, 0xf1, 0x47, 0xa7, 0xa1, 0x75, 0xb6, 0xca, 0x6f, 0x8e, - 0x02, 0xe4, 0x91, 0x50, 0xf1, 0xc4, 0xfa, 0xd6, 0xef, 0xcb, 0x95, 0x55, 0xbe, 0x2b, 0x5a, 0x3b, - 0xc6, 0xb6, 0x8d, 0x92, 0xb6, 0x71, 0xe7, 0x2b, 0xa7, 0x65, 0xe5, 0xbf, 0xdb, 0x6d, 0x34, 0xf8, - 0x9d, 0x75, 0xa6, 0xb1, 0xf1, 0x47, 0x93, 0xdb, 0x8d, 0x59, 0x8d, 0x66, 0xeb, 0xb7, 0x3f, 0xe6, - 0x17, 0xb6, 0x1e, 0x71, 0x3e, 0xca, 0xb2, 0xec, 0x5b, 0xdf, 0x70, 0x7a, 0x6d, 0xd6, 0x76, 0xed, - 0x2c, 0x73, 0x6a, 0xd7, 0xdf, 0x81, 0x09, 0x57, 0xef, 0x4e, 0x2f, 0x16, 0x57, 0x57, 0xc0, 0xba, - 0x8b, 0xd3, 0x72, 0x3c, 0x3e, 0x0e, 0xe6, 0x08, 0x03, 0xfc, 0x50, 0xe6, 0x37, 0xe3, 0x71, 0x74, - 0xb7, 0xf1, 0xbe, 0x41, 0xeb, 0x31, 0x61, 0x30, 0x27, 0x7f, 0xbd, 0x3c, 0xb2, 0xe3, 0xb1, 0x3d, - 0xad, 0xf5, 0xde, 0xd7, 0x4e, 0x2f, 0xd6, 0x2b, 0xf0, 0x9d, 0xcd, 0x85, 0x5d, 0x1b, 0x98, 0x56, - 0x20, 0x79, 0x17, 0x7b, 0x67, 0xba, 0x0f, 0xcf, 0x51, 0xd7, 0x64, 0xba, 0x26, 0xa7, 0xa6, 0x4d, - 0x74, 0x8c, 0xe2, 0xd3, 0xcd, 0xf5, 0xe5, 0xc2, 0xe6, 0xd0, 0x35, 0xb3, 0xf3, 0x28, 0xde, 0xed, - 0x26, 0x2d, 0x35, 0xf4, 0x03, 0x3d, 0x58, 0xc1, 0xc4, 0xab, 0x19, 0x9a, 0x67, 0xab, 0x19, 0x16, - 0xbe, 0x74, 0x05, 0x71, 0x05, 0x75, 0x05, 0x73, 0x05, 0x77, 0x85, 0xef, 0x95, 0xae, 0x50, 0xae, - 0xd0, 0x9e, 0xb8, 0x66, 0xf4, 0x3c, 0xd8, 0x33, 0x61, 0xcf, 0x85, 0x3d, 0x1b, 0x06, 0x3e, 0x94, - 0xda, 0xa2, 0xac, 0x4e, 0xdf, 0x5e, 0xad, 0x2f, 0x7e, 0xaa, 0xb2, 0x55, 0xf3, 0xcb, 0x63, 0x52, - 0x99, 0x9d, 0xe4, 0x57, 0x10, 0x2e, 0xbd, 0x2b, 0x14, 0xf7, 0xbb, 0x42, 0xc8, 0xb3, 0xe7, 0x15, - 0x45, 0x3c, 0x1c, 0x60, 0xcf, 0x3f, 0x8a, 0x78, 0xe7, 0x87, 0x08, 0x69, 0x20, 0x28, 0x1e, 0xf9, - 0x37, 0xaf, 0x87, 0x2c, 0x50, 0x56, 0x7f, 0x71, 0xf3, 0x25, 0xcd, 0x97, 0xd6, 0xdf, 0xca, 0x2e, - 0x8c, 0xad, 0xab, 0x6f, 0x6f, 0x6d, 0x5e, 0x35, 0xbd, 0x6f, 0x7c, 0xbd, 0x01, 0xbe, 0x2c, 0x57, - 0x10, 0xf0, 0xbf, 0xe4, 0x97, 0x4d, 0xe7, 0xa2, 0x2a, 0xa0, 0x7e, 0x8c, 0xdb, 0x5e, 0x08, 0x96, - 0xec, 0x18, 0xed, 0x36, 0x81, 0xf3, 0xd5, 0x26, 0x1b, 0x58, 0x1a, 0x34, 0x74, 0x3c, 0x14, 0xd7, - 0xe8, 0x0b, 0xb2, 0x40, 0xeb, 0x50, 0x2e, 0xa2, 0x46, 0x95, 0x77, 0xdb, 0x11, 0x24, 0x94, 0xca, - 0x73, 0xb5, 0x7e, 0xe7, 0x1b, 0x6c, 0x61, 0xd6, 0x37, 0x47, 0xc6, 0x11, 0xae, 0x36, 0x57, 0x57, - 0xe0, 0x61, 0x36, 0x6c, 0x2b, 0x9d, 0x23, 0x1e, 0xf4, 0xc0, 0xf8, 0x4e, 0x40, 0xda, 0xb8, 0x33, - 0xdf, 0xf1, 0x30, 0xea, 0xa0, 0x6b, 0xbb, 0x05, 0x71, 0x77, 0x43, 0x03, 0x7a, 0xe2, 0x6e, 0xcc, - 0xc2, 0x21, 0x5f, 0xae, 0x4d, 0xe4, 0xa0, 0x2c, 0xd2, 0x25, 0xc4, 0x37, 0x4a, 0xd7, 0x99, 0x3d, - 0xbd, 0xca, 0x57, 0xef, 0x6c, 0x91, 0xde, 0x66, 0x81, 0xd9, 0xd2, 0x4d, 0x16, 0xfa, 0xc1, 0x64, - 0x35, 0x5d, 0x4f, 0x3c, 0xc4, 0x40, 0xaf, 0x10, 0x8d, 0x7b, 0x5a, 0xbe, 0x75, 0xae, 0x7d, 0xeb, - 0x5c, 0x3b, 0xf5, 0xa5, 0xab, 0xbb, 0x82, 0xb8, 0x82, 0xba, 0x82, 0xb9, 0x82, 0xbb, 0xc2, 0xf7, - 0x4a, 0x57, 0x28, 0x57, 0x68, 0x4f, 0x5c, 0xb3, 0x7b, 0x1e, 0xec, 0x99, 0xb0, 0xe7, 0xc2, 0x9e, - 0xcd, 0x3b, 0x78, 0x9c, 0x16, 0xb1, 0xf7, 0x60, 0x87, 0x64, 0x19, 0x78, 0x86, 0x9b, 0xe2, 0x78, - 0xbc, 0x9c, 0x0a, 0x36, 0x49, 0x92, 0x55, 0xbc, 0x99, 0x2d, 0x93, 0x64, 0x9e, 0xd9, 0xd9, 0x6a, - 0x5e, 0xeb, 0xed, 0x11, 0xfa, 0xdb, 0xd9, 0xf2, 0xec, 0x8c, 0xcc, 0xb7, 0x9e, 0x63, 0x3a, 0xcd, - 0x67, 0x74, 0xec, 0x04, 0x04, 0x21, 0xf3, 0x88, 0x80, 0x68, 0x01, 0xaa, 0xbc, 0x28, 0x16, 0xe6, - 0xab, 0xf5, 0x65, 0xfe, 0xa5, 0x8d, 0x56, 0x71, 0x3c, 0x85, 0x15, 0xe3, 0x75, 0x33, 0x91, 0xc5, - 0xab, 0xc5, 0x94, 0x20, 0xa6, 0x5e, 0x47, 0x4d, 0x03, 0xd6, 0x64, 0xbb, 0x38, 0x3b, 0x13, 0x69, - 0xfb, 0x9b, 0xa8, 0xad, 0xa0, 0xe3, 0x45, 0x0c, 0x84, 0x9c, 0x13, 0x2d, 0xb6, 0xd0, 0x9d, 0x71, - 0x49, 0x19, 0xeb, 0x78, 0x08, 0x61, 0x8e, 0x07, 0x93, 0x90, 0xc9, 0x09, 0x19, 0x0b, 0x7a, 0x57, - 0x0e, 0xcc, 0x48, 0x70, 0x4e, 0x45, 0x12, 0x45, 0x18, 0x11, 0xd7, 0x34, 0x9d, 0x62, 0xb4, 0xf5, - 0xf5, 0xc1, 0x54, 0xdd, 0xf4, 0xe3, 0x96, 0x9f, 0x30, 0xe4, 0xc7, 0x50, 0x7b, 0x63, 0x60, 0xb2, - 0x37, 0xc8, 0xa1, 0x71, 0x9f, 0xa4, 0xee, 0x43, 0xda, 0xea, 0xcc, 0xb0, 0xe8, 0x6d, 0xd0, 0x69, - 0xae, 0xeb, 0x8c, 0x5a, 0xe5, 0xc5, 0x3d, 0x55, 0x1a, 0xf4, 0xb6, 0x53, 0xe9, 0x7b, 0xef, 0xd5, - 0x6a, 0xcf, 0xd1, 0x29, 0xf6, 0xb0, 0xc0, 0x06, 0xee, 0x33, 0x46, 0x7c, 0xa6, 0xfe, 0x83, 0xd9, - 0xb4, 0x26, 0x78, 0x70, 0x36, 0xde, 0x20, 0xff, 0xc7, 0xf9, 0xd6, 0x59, 0xf8, 0x6a, 0x51, 0x59, - 0x97, 0x52, 0xbf, 0x59, 0x5d, 0xe6, 0x1f, 0xb2, 0x65, 0xda, 0xe7, 0xdb, 0x24, 0x5b, 0x9e, 0xf4, - 0xf6, 0x4c, 0x97, 0x67, 0x99, 0x00, 0x1d, 0x06, 0xa9, 0x79, 0x79, 0x22, 0x58, 0xda, 0x65, 0x84, - 0x28, 0x4e, 0x07, 0xd9, 0x01, 0xc5, 0xaf, 0x42, 0xda, 0x5d, 0xb3, 0x76, 0xf6, 0xf2, 0xcf, 0x18, - 0xd1, 0x4c, 0x0b, 0x49, 0x34, 0xef, 0x32, 0xcb, 0x9b, 0x7a, 0xe0, 0x9e, 0xe8, 0x8b, 0x8e, 0x48, - 0x4c, 0xa7, 0x28, 0xdd, 0x5f, 0x0d, 0x7c, 0xf5, 0xd7, 0x3d, 0x4d, 0x3d, 0x87, 0xdd, 0x2e, 0x0d, - 0x33, 0x7e, 0x9b, 0xd5, 0xb3, 0x60, 0x23, 0x79, 0x5f, 0xca, 0xdf, 0x5b, 0x51, 0x8e, 0x51, 0xbd, - 0xc3, 0x1c, 0xa4, 0x49, 0x93, 0xdd, 0xd5, 0xda, 0xc4, 0xce, 0x4c, 0xad, 0xe7, 0x0a, 0x74, 0x6b, - 0xe6, 0xa9, 0x01, 0x8f, 0x13, 0xc3, 0x6c, 0xb9, 0xdd, 0x0e, 0x14, 0xe5, 0xf2, 0xa6, 0xf5, 0x79, - 0xd3, 0x97, 0xae, 0xee, 0x0a, 0xe2, 0x0a, 0xea, 0x0a, 0xe6, 0x0a, 0xee, 0x0a, 0xdf, 0x2b, 0x5d, - 0xa1, 0x5c, 0xa1, 0x3d, 0x71, 0xcd, 0xee, 0x79, 0xb0, 0x67, 0xc2, 0x9e, 0x0b, 0x7b, 0xb6, 0x26, - 0x6f, 0x36, 0x3f, 0x3b, 0x35, 0x4d, 0xa7, 0x34, 0xad, 0x3b, 0x03, 0x5d, 0x43, 0xe3, 0x36, 0x30, - 0x09, 0xc0, 0xd0, 0xa1, 0x49, 0xf7, 0x34, 0xe9, 0x1a, 0x43, 0x2d, 0x36, 0x3b, 0xf0, 0xb4, 0x4c, - 0x61, 0xa9, 0x4c, 0x73, 0xd8, 0x04, 0x07, 0xba, 0x9a, 0xf4, 0x6b, 0xf0, 0x6b, 0x93, 0x45, 0x91, - 0xfb, 0xb3, 0xfe, 0x6f, 0x01, 0xf0, 0x4f, 0x84, 0x42, 0x4a, 0x0a, 0x4d, 0x25, 0xf8, 0xa4, 0xdc, - 0x5a, 0x37, 0x34, 0x8f, 0x4f, 0x88, 0xc4, 0x92, 0x52, 0x25, 0x35, 0x58, 0x3b, 0x3e, 0x8f, 0x4a, - 0xa0, 0x87, 0xbf, 0xbe, 0xf9, 0x3c, 0x2a, 0xa0, 0x09, 0xfe, 0x4e, 0xa0, 0x81, 0x70, 0xc5, 0xb0, - 0x66, 0xe7, 0x04, 0x21, 0x46, 0xb1, 0x42, 0x12, 0x8f, 0x6d, 0x9c, 0x2c, 0x40, 0x97, 0x27, 0x18, - 0x4b, 0x45, 0x91, 0x44, 0x2e, 0xa4, 0x30, 0xd9, 0x16, 0x4e, 0x3c, 0x8a, 0x13, 0xeb, 0xc4, 0x8e, - 0x43, 0x79, 0xb0, 0x62, 0x02, 0x07, 0x71, 0x1c, 0x44, 0x30, 0x60, 0x92, 0xdc, 0xb1, 0xc8, 0x6d, - 0x09, 0x2c, 0x98, 0xc7, 0x49, 0x51, 0xb3, 0x14, 0x0d, 0x25, 0x05, 0x4a, 0x8a, 0x05, 0xe1, 0x9a, - 0x20, 0x0d, 0x94, 0x84, 0x6c, 0x8d, 0xa3, 0x04, 0xe1, 0x25, 0x50, 0xbe, 0x8a, 0x1a, 0x7f, 0x29, - 0x50, 0xeb, 0x2b, 0x05, 0x86, 0x93, 0x48, 0xb3, 0xc3, 0x49, 0xbd, 0x22, 0x92, 0x56, 0x13, 0x89, - 0xc7, 0xd2, 0xec, 0x7a, 0xe2, 0x73, 0x33, 0x8e, 0xca, 0xf3, 0xc2, 0x0f, 0x13, 0x28, 0x48, 0x84, - 0x0a, 0x4a, 0x4c, 0xa0, 0x18, 0x60, 0x37, 0x8d, 0x42, 0xa0, 0x5a, 0x9e, 0xdb, 0x31, 0xfc, 0x2e, - 0xe3, 0x46, 0x05, 0x54, 0x69, 0x2e, 0x18, 0x57, 0xe2, 0x5e, 0x15, 0xd8, 0x73, 0xd3, 0x20, 0x4f, - 0x04, 0x12, 0x18, 0x71, 0x85, 0xf5, 0xa3, 0xc0, 0x11, 0x63, 0x9c, 0x70, 0x4a, 0xd1, 0x5d, 0xe0, - 0xf1, 0x5d, 0x68, 0x45, 0x08, 0x88, 0x01, 0xbb, 0x14, 0x0c, 0x2b, 0xa5, 0xe5, 0xe7, 0x00, 0xe2, - 0xf3, 0x04, 0x83, 0x9d, 0x91, 0x42, 0x8c, 0x3c, 0x8c, 0x48, 0xc0, 0x48, 0x0c, 0x9c, 0x83, 0x62, - 0xca, 0xf0, 0x83, 0x90, 0xe4, 0xfc, 0x84, 0x71, 0x89, 0xb8, 0x56, 0xf4, 0x2e, 0xa0, 0x47, 0xf0, - 0x28, 0x98, 0x8f, 0x94, 0x08, 0x51, 0xce, 0xf0, 0x67, 0x59, 0x48, 0xc3, 0x34, 0xb5, 0x73, 0x60, - 0xc6, 0xb0, 0x7c, 0x10, 0x10, 0x44, 0xfb, 0x09, 0x23, 0xc8, 0xe7, 0xf6, 0xc3, 0x60, 0xb0, 0xf3, - 0x7a, 0xad, 0x11, 0x43, 0x30, 0x21, 0xf2, 0x6c, 0x3c, 0x90, 0x46, 0x12, 0x08, 0x21, 0x26, 0x10, - 0x15, 0x8a, 0x7c, 0x96, 0xcb, 0x81, 0x87, 0x30, 0x04, 0x3a, 0xc7, 0x08, 0x3f, 0x8c, 0xc7, 0xf9, - 0x02, 0x47, 0x60, 0x4d, 0x42, 0x34, 0x7a, 0x18, 0x94, 0x37, 0x3b, 0x15, 0x9c, 0x72, 0x4a, 0xee, - 0x09, 0xb7, 0x1e, 0x54, 0x3b, 0x25, 0x98, 0xcd, 0xb8, 0x87, 0x08, 0xe8, 0x06, 0x31, 0x81, 0x05, - 0x97, 0x5a, 0x70, 0xec, 0x46, 0xe5, 0x35, 0x40, 0xd9, 0x02, 0xec, 0xbd, 0x07, 0x09, 0xcd, 0x11, - 0x16, 0xd4, 0xa9, 0x41, 0xd7, 0x28, 0x68, 0x83, 0xc2, 0x01, 0xee, 0x34, 0x61, 0x9d, 0x02, 0x03, - 0xfd, 0x27, 0x82, 0x51, 0x48, 0x2c, 0x12, 0x7b, 0x4b, 0xb1, 0x1a, 0x94, 0x6a, 0x40, 0xf5, 0x81, - 0x4d, 0x25, 0x84, 0xa6, 0xa4, 0xc8, 0x1b, 0x09, 0xd5, 0x78, 0xc8, 0x67, 0xe0, 0xe1, 0xf3, 0x13, - 0x89, 0x30, 0x87, 0x08, 0xd7, 0xf8, 0x20, 0x1e, 0x70, 0x9e, 0x84, 0x2a, 0x40, 0x83, 0xbc, 0x93, - 0x3f, 0x1d, 0x0e, 0x48, 0x17, 0x02, 0xb9, 0x8c, 0x48, 0xf9, 0x61, 0x38, 0xcc, 0xd9, 0x1c, 0x36, - 0x3d, 0x52, 0x31, 0xf5, 0x42, 0x38, 0x7a, 0x9e, 0x70, 0xa1, 0x18, 0x03, 0x25, 0xaa, 0xc3, 0x70, - 0x9c, 0xef, 0x20, 0xac, 0x15, 0xb8, 0xa9, 0xf7, 0x9d, 0x27, 0x03, 0x72, 0xf9, 0x4b, 0x49, 0x2a, - 0xa8, 0x16, 0xf8, 0x30, 0x1e, 0x17, 0xd6, 0x60, 0x79, 0x4e, 0xc1, 0x41, 0xf1, 0x0b, 0x01, 0xb9, - 0x80, 0x80, 0xe8, 0x66, 0x42, 0x61, 0x26, 0xe4, 0x41, 0x48, 0xb0, 0xf6, 0x70, 0x0c, 0x81, 0x03, - 0x2a, 0x7c, 0x0e, 0x1e, 0xe9, 0x12, 0x90, 0x0b, 0x0b, 0x05, 0xc9, 0xee, 0x30, 0x20, 0xec, 0x96, - 0x36, 0x4d, 0xc0, 0x94, 0x12, 0x36, 0xc1, 0x0f, 0x21, 0xca, 0xb3, 0x0e, 0x54, 0x54, 0x65, 0x0e, - 0xc4, 0x79, 0x87, 0xab, 0x02, 0x69, 0xb5, 0xc7, 0xc1, 0x34, 0xc1, 0xe3, 0x40, 0x0e, 0xab, 0xc1, - 0xa8, 0x06, 0x4c, 0xad, 0xbc, 0x13, 0x02, 0x31, 0xcd, 0x25, 0x60, 0xf6, 0x53, 0xc2, 0x35, 0x18, - 0xdc, 0x81, 0x09, 0xd2, 0x48, 0x0e, 0xf0, 0x9b, 0xb0, 0xc1, 0x8a, 0x6a, 0x44, 0x11, 0xf7, 0x69, - 0x0b, 0x8b, 0x1a, 0x87, 0x68, 0x70, 0xb4, 0x56, 0x07, 0xa8, 0x48, 0x73, 0xee, 0x72, 0x2d, 0xa1, - 0x1e, 0x82, 0xfe, 0x0c, 0x04, 0x2e, 0x07, 0x38, 0x41, 0xb0, 0x7a, 0x0b, 0x74, 0x3f, 0x0a, 0xe6, - 0x52, 0x8e, 0x24, 0x4a, 0x83, 0xe3, 0x3f, 0x15, 0x85, 0x74, 0x62, 0x39, 0xd3, 0xb2, 0x4e, 0x1a, - 0xf7, 0x62, 0x40, 0xce, 0x73, 0x35, 0x18, 0x0b, 0x09, 0x86, 0x5e, 0x88, 0x82, 0x42, 0xae, 0x51, - 0x30, 0x4b, 0x8d, 0x25, 0xbb, 0x1f, 0x85, 0xcb, 0x33, 0x5c, 0x41, 0x60, 0x12, 0x42, 0x9e, 0x08, - 0x02, 0xdc, 0x15, 0xa8, 0x39, 0xc1, 0x5a, 0xea, 0x03, 0x20, 0xc4, 0x3c, 0x91, 0x02, 0x11, 0x8d, - 0x95, 0x7e, 0x19, 0x02, 0x58, 0xfd, 0x40, 0x0b, 0x54, 0x30, 0xa6, 0xe4, 0xfd, 0x00, 0x9c, 0xe3, - 0x32, 0x82, 0x15, 0xe6, 0xaa, 0x4e, 0x40, 0x4f, 0x71, 0x26, 0x58, 0x2e, 0xc0, 0xba, 0x92, 0x01, - 0x0a, 0x74, 0x00, 0x02, 0x88, 0xd5, 0x1a, 0xf6, 0x30, 0x0a, 0x96, 0x81, 0x07, 0x30, 0xf4, 0xf1, - 0x1d, 0x46, 0x77, 0x64, 0xb6, 0x9f, 0xba, 0x3c, 0x0e, 0x59, 0x48, 0x50, 0x04, 0x19, 0x0b, 0xc4, - 0x88, 0x1a, 0x80, 0x68, 0x00, 0x6c, 0x3f, 0x95, 0x5d, 0x90, 0xc2, 0xbe, 0x52, 0x69, 0xcc, 0x30, - 0xaf, 0x8f, 0x83, 0x1e, 0x04, 0x69, 0x41, 0x84, 0xc1, 0x1d, 0x15, 0xdb, 0x4f, 0x41, 0x96, 0x63, - 0x2e, 0x0f, 0x31, 0x8d, 0x3c, 0x1f, 0xaf, 0x81, 0xc8, 0x06, 0xc8, 0xf6, 0x93, 0x6d, 0x97, 0x00, - 0x88, 0x36, 0xea, 0x52, 0xb0, 0xc3, 0x82, 0xeb, 0xd0, 0xc6, 0xcf, 0x05, 0xe3, 0x17, 0x7f, 0xd8, - 0xcc, 0x30, 0x88, 0x6d, 0x89, 0x0f, 0xc3, 0xf1, 0x39, 0x14, 0xce, 0x5a, 0x0a, 0xd2, 0x89, 0x78, - 0x06, 0x1c, 0xef, 0xfa, 0x1c, 0x73, 0x42, 0x1f, 0xc0, 0x82, 0x5d, 0xf6, 0x00, 0xc0, 0x04, 0xdc, - 0x5a, 0xbf, 0x04, 0x8d, 0xcb, 0xe1, 0x90, 0xe9, 0x61, 0xff, 0x47, 0xb9, 0x3e, 0x0c, 0xc6, 0xad, - 0x70, 0x10, 0x8b, 0x70, 0x52, 0xf0, 0x16, 0x7c, 0x22, 0x16, 0xb7, 0x3f, 0xe0, 0xc2, 0xad, 0x40, - 0xb0, 0xaa, 0x3e, 0x84, 0x06, 0x42, 0x14, 0x43, 0xa2, 0xc1, 0x1c, 0x0b, 0xf6, 0x22, 0x38, 0xde, - 0x17, 0x38, 0xe8, 0x0e, 0x8e, 0x33, 0x0f, 0xa0, 0xf1, 0x87, 0x1e, 0x48, 0xbf, 0x18, 0x56, 0x12, - 0xfd, 0x74, 0x3c, 0x60, 0x79, 0x09, 0xda, 0x52, 0x92, 0x78, 0x5d, 0x1d, 0x82, 0x03, 0xf1, 0x4a, - 0xc1, 0xcf, 0xc0, 0x3f, 0xea, 0xa8, 0xd9, 0x03, 0x13, 0x1c, 0xf5, 0xa2, 0xee, 0x72, 0x37, 0xe9, - 0x8e, 0x68, 0xb4, 0xa3, 0x29, 0x70, 0x66, 0x06, 0x87, 0xbc, 0xb4, 0xbd, 0xfb, 0x2d, 0x83, 0x13, - 0x5d, 0xdf, 0x4e, 0xb3, 0x22, 0x69, 0xc9, 0xd5, 0x70, 0xa4, 0xec, 0x18, 0xc7, 0xaf, 0xfa, 0xd1, - 0xea, 0xaf, 0xc7, 0xda, 0x0d, 0xd5, 0x7c, 0xbd, 0xa6, 0xba, 0x81, 0x9a, 0x6f, 0x30, 0xf1, 0xf6, - 0xc6, 0xb9, 0xa0, 0x35, 0xe8, 0xbd, 0x43, 0xaf, 0xbb, 0x17, 0xe9, 0xcf, 0xbc, 0x83, 0x5b, 0x82, - 0x28, 0x0e, 0xef, 0x08, 0x0e, 0x9c, 0xf9, 0xda, 0x9b, 0x6b, 0x3a, 0x69, 0xee, 0x40, 0x8a, 0x19, - 0x98, 0x90, 0x8d, 0x5d, 0xb6, 0x2a, 0xc0, 0x0d, 0xc7, 0xd6, 0x7d, 0xad, 0xbf, 0xe1, 0xa9, 0xdb, - 0xa0, 0xae, 0xfa, 0x2a, 0x41, 0x7d, 0x1d, 0x8b, 0xa0, 0x3d, 0xa4, 0x69, 0xc5, 0x99, 0x81, 0x64, - 0xd3, 0x34, 0x75, 0x92, 0x4d, 0x2f, 0xd9, 0x04, 0x92, 0x4d, 0x20, 0xd9, 0x04, 0x92, 0x4d, 0x20, - 0xb9, 0x1c, 0x48, 0x2e, 0x9b, 0xa6, 0x4e, 0x72, 0xd9, 0x4b, 0x2e, 0x03, 0xc9, 0x65, 0x20, 0xb9, - 0x0c, 0x24, 0x97, 0x81, 0xe4, 0x6a, 0x20, 0xb9, 0x6a, 0x9a, 0x3a, 0xc9, 0x55, 0x2f, 0xb9, 0x0a, - 0x24, 0x57, 0x81, 0xe4, 0x2a, 0x90, 0x5c, 0xb5, 0x92, 0x87, 0x66, 0x6c, 0x1f, 0x9d, 0xb2, 0x3d, - 0xdb, 0x0e, 0x88, 0xea, 0x37, 0xbb, 0x97, 0x99, 0xbb, 0xd8, 0x33, 0xf7, 0x8c, 0x70, 0x30, 0x71, - 0xea, 0x6d, 0x0a, 0xd5, 0xb4, 0xb6, 0x62, 0x53, 0x83, 0x99, 0xba, 0x9a, 0x23, 0x31, 0xa9, 0x69, - 0x49, 0x4c, 0x47, 0x62, 0x06, 0x24, 0x65, 0x5a, 0xb6, 0x24, 0x65, 0x47, 0x52, 0x0e, 0x48, 0x8a, - 0xb4, 0x68, 0x49, 0x8a, 0x8e, 0xa4, 0x68, 0x49, 0xf6, 0x74, 0xe2, 0x1f, 0x24, 0xb3, 0xbb, 0x0a, - 0xb8, 0x4b, 0x54, 0x3f, 0x33, 0x3c, 0xae, 0x98, 0xfd, 0x07, 0x26, 0x58, 0x7a, 0x41, 0x49, 0xfb, - 0xef, 0x46, 0x36, 0x6e, 0x43, 0xc1, 0xf8, 0x9b, 0xb0, 0x56, 0x9b, 0xfe, 0x16, 0xac, 0x51, 0xa8, - 0xf1, 0xb7, 0x61, 0xed, 0xb5, 0x89, 0xbf, 0x15, 0xab, 0xd5, 0x9a, 0xda, 0x21, 0x88, 0xfa, 0xc9, - 0x22, 0x3b, 0x30, 0xe5, 0x21, 0xa9, 0x7f, 0x72, 0x0d, 0x51, 0xb4, 0xef, 0x23, 0xcd, 0x2d, 0x56, - 0x36, 0x1a, 0xb5, 0xe1, 0xea, 0x65, 0x44, 0x71, 0x9a, 0x67, 0x68, 0x92, 0x43, 0x5e, 0x9c, 0xc4, - 0x36, 0xab, 0x66, 0xb9, 0xbb, 0x57, 0x35, 0x6d, 0xa5, 0x6c, 0x2b, 0x90, 0xbf, 0x97, 0x33, 0x9f, - 0x97, 0xe7, 0xc9, 0x72, 0x26, 0x28, 0x1c, 0x76, 0xdd, 0xa6, 0xc6, 0xe5, 0x48, 0x16, 0xb7, 0x4d, - 0x90, 0x85, 0x88, 0xcf, 0xae, 0xa2, 0x6d, 0x2a, 0xe7, 0xad, 0x1e, 0xbc, 0xec, 0x7d, 0x39, 0x4e, - 0xc6, 0x58, 0xc0, 0x42, 0x32, 0xca, 0xb2, 0xd1, 0x2e, 0x6d, 0x1e, 0xb1, 0x7f, 0xbe, 0xe4, 0x77, - 0xee, 0xe0, 0xb2, 0xdb, 0xc8, 0xbf, 0x3e, 0xc7, 0x13, 0x7b, 0x7a, 0x61, 0xf2, 0xc1, 0x03, 0xd7, - 0xf0, 0xd9, 0x72, 0x97, 0xda, 0x3b, 0x4f, 0x60, 0xfd, 0xcb, 0x66, 0xcb, 0x1d, 0x05, 0x4f, 0x9b, - 0xbb, 0x49, 0xab, 0x24, 0x03, 0xaa, 0x30, 0xd3, 0x45, 0xf3, 0x80, 0x34, 0x49, 0x12, 0x53, 0x0f, - 0x5f, 0x66, 0x8b, 0x99, 0x99, 0x4f, 0xec, 0xac, 0x9c, 0xc3, 0x44, 0xca, 0xb8, 0xbb, 0xeb, 0xdd, - 0x45, 0x31, 0xfc, 0x9f, 0xfc, 0xea, 0x7f, 0xf1, 0xc2, 0x99, 0x50, 0xc3, 0x1f, 0x00, 0x00, -}; -const StaticFile md5_js PROGMEM = {(sizeof(md5_js_content)/sizeof(md5_js_content[0])), md5_js_content}; - -static const uint8_t style_css_content[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x9d, 0x53, 0x5d, 0x6b, 0xdb, 0x30, - 0x14, 0x7d, 0xdf, 0xaf, 0x08, 0x94, 0x41, 0x0b, 0x76, 0xb0, 0x9b, 0x26, 0x59, 0x64, 0xf6, 0xb0, - 0x3d, 0x8c, 0xed, 0x61, 0x4f, 0x65, 0x4f, 0xa3, 0x14, 0x7d, 0x5c, 0xd9, 0x22, 0xb2, 0x25, 0xa4, - 0xeb, 0x26, 0x99, 0xf1, 0x7f, 0x9f, 0xfc, 0x11, 0x37, 0x69, 0x32, 0x28, 0xc3, 0x20, 0xb8, 0x1f, - 0xd2, 0x39, 0xf7, 0xdc, 0x63, 0x66, 0xc4, 0x21, 0x2a, 0xb0, 0xd4, 0x8d, 0xa5, 0x42, 0xa8, 0x2a, - 0x27, 0x49, 0x56, 0x52, 0x97, 0xab, 0x8a, 0x24, 0x2d, 0xeb, 0x8a, 0xac, 0x46, 0x34, 0x55, 0xa4, - 0x2a, 0x5b, 0xe3, 0x6f, 0x3c, 0x58, 0xf8, 0x6c, 0xa9, 0xf7, 0x3b, 0xe3, 0xc4, 0xd3, 0x69, 0x12, - 0x61, 0x8f, 0x4f, 0x8d, 0x34, 0x15, 0xc6, 0x5e, 0xfd, 0x01, 0x92, 0xae, 0xec, 0x3e, 0xeb, 0x43, - 0x49, 0x4b, 0xa5, 0x0f, 0x24, 0xa6, 0xd6, 0x6a, 0x88, 0xfd, 0xc1, 0x23, 0x94, 0xd1, 0x57, 0xad, - 0xaa, 0xed, 0x4f, 0xca, 0x1f, 0xfb, 0xf0, 0x5b, 0xe8, 0x8b, 0x1e, 0x21, 0x37, 0x30, 0xfb, 0xf5, - 0x23, 0xfa, 0x0e, 0xfa, 0x05, 0x50, 0x71, 0x1a, 0x7d, 0x71, 0x8a, 0xea, 0xc8, 0xd3, 0xca, 0xc7, - 0x1e, 0x9c, 0x92, 0xed, 0x1c, 0x15, 0x6a, 0x98, 0xb8, 0xa6, 0x89, 0xdd, 0xcf, 0xfa, 0x63, 0x42, - 0xdb, 0x81, 0xca, 0x0b, 0x24, 0xab, 0x24, 0xc9, 0x18, 0xe5, 0xdb, 0xdc, 0x99, 0xba, 0x12, 0x31, - 0x37, 0xda, 0x38, 0x72, 0x03, 0x52, 0xde, 0xcb, 0x65, 0xc6, 0x02, 0x79, 0x70, 0x31, 0x33, 0x61, - 0xb2, 0x92, 0xa4, 0xe1, 0xba, 0x37, 0x5a, 0x89, 0xd9, 0x8d, 0xd8, 0x40, 0x02, 0xeb, 0x6c, 0xec, - 0xbe, 0x5f, 0xaf, 0x80, 0x3d, 0x64, 0x27, 0x33, 0x2d, 0xed, 0xbe, 0x9d, 0x33, 0x6d, 0xf8, 0xf6, - 0x8c, 0x42, 0x3b, 0x97, 0xb5, 0xd6, 0xf1, 0x4e, 0x09, 0x2c, 0x9a, 0xfe, 0x0c, 0xe9, 0xe4, 0x63, - 0xc0, 0xd9, 0x77, 0x17, 0xbb, 0xb6, 0x09, 0xb2, 0x6b, 0x36, 0xae, 0x7c, 0xd6, 0x94, 0xc1, 0x89, - 0xe8, 0xb3, 0x64, 0xb6, 0xb8, 0x1c, 0x61, 0xec, 0xed, 0x65, 0x6e, 0x86, 0xb5, 0x4c, 0xac, 0x7b, - 0x2e, 0x7d, 0xd9, 0xd7, 0xec, 0xec, 0xb5, 0x18, 0x8d, 0x25, 0xe1, 0xb5, 0xf6, 0x5d, 0x3b, 0x8b, - 0x3c, 0x68, 0xe0, 0xd8, 0x8c, 0x0c, 0x1d, 0x15, 0xaa, 0xf6, 0xe4, 0x21, 0x90, 0x19, 0x32, 0xa7, - 0xfa, 0xf0, 0x0d, 0xe7, 0x5c, 0x66, 0x47, 0xd6, 0xeb, 0x50, 0xd9, 0x84, 0x46, 0x53, 0x63, 0x58, - 0x27, 0x04, 0xc7, 0x5c, 0x43, 0x24, 0xd2, 0xf0, 0xda, 0x5f, 0xe0, 0x8e, 0xe9, 0x01, 0x7d, 0x08, - 0x9a, 0x5e, 0xb0, 0x82, 0x0a, 0xb3, 0xeb, 0x15, 0xe9, 0x37, 0xeb, 0x72, 0x46, 0x6f, 0x93, 0xa8, - 0xfb, 0xe6, 0xe9, 0xf2, 0xae, 0x1d, 0xfc, 0x48, 0x84, 0xf2, 0x94, 0x69, 0x10, 0x57, 0x8d, 0x79, - 0xb5, 0x3a, 0xa0, 0x4e, 0x95, 0x11, 0xf8, 0x18, 0x37, 0x97, 0x6e, 0x91, 0x69, 0x70, 0xcb, 0xe2, - 0xe8, 0x96, 0xb3, 0xe4, 0xc8, 0xe2, 0x7f, 0x45, 0xeb, 0x96, 0xf7, 0xaa, 0xda, 0x89, 0x51, 0xc3, - 0xfb, 0x52, 0x1e, 0xfd, 0x97, 0x04, 0x0f, 0x5b, 0xe3, 0x15, 0xaa, 0x30, 0xaf, 0x03, 0x4d, 0x51, - 0xbd, 0x40, 0xd6, 0xdd, 0x89, 0x8b, 0xc1, 0x22, 0xe9, 0xa7, 0x2b, 0x9e, 0x19, 0x05, 0xaa, 0x0c, - 0xde, 0x4e, 0xd3, 0xdd, 0x91, 0xc2, 0xbc, 0x80, 0x7b, 0x8f, 0xc0, 0x19, 0xaf, 0x9d, 0x0f, 0xf0, - 0xd6, 0xa8, 0x0a, 0xc1, 0xbd, 0x19, 0x9f, 0x2d, 0x39, 0x87, 0xc5, 0xf9, 0x1f, 0xf2, 0x0f, 0x44, - 0xca, 0x3b, 0xbe, 0x4d, 0x67, 0xc6, 0xa0, 0xc6, 0xd8, 0x34, 0x57, 0xfe, 0xd9, 0x81, 0x07, 0x8c, - 0xde, 0xc4, 0xd7, 0xf9, 0x1e, 0xff, 0xdb, 0xd5, 0x62, 0x93, 0xae, 0xdb, 0x0f, 0x7f, 0x01, 0x37, - 0xdb, 0x6e, 0xf6, 0xae, 0x04, 0x00, 0x00, -}; -const StaticFile style_css PROGMEM = {(sizeof(style_css_content)/sizeof(style_css_content[0])), style_css_content}; - -static const uint8_t favicon_ico_content[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0x99, 0x4b, 0x48, 0x15, 0x61, - 0x14, 0xc7, 0xcf, 0xc5, 0x17, 0x2e, 0x4a, 0x57, 0xe5, 0x63, 0xe1, 0x85, 0x42, 0x23, 0x8c, 0x8c, - 0x20, 0x4d, 0x45, 0xdb, 0x59, 0x14, 0x2e, 0x7a, 0xab, 0x68, 0x1b, 0x17, 0xae, 0x24, 0x41, 0xf1, - 0x41, 0xa0, 0x41, 0xa1, 0x11, 0x28, 0x1a, 0x2e, 0x12, 0x72, 0xe7, 0x03, 0x09, 0x74, 0x15, 0x54, - 0x1b, 0x97, 0xd9, 0x53, 0x23, 0x8a, 0x5a, 0x94, 0x25, 0x59, 0x91, 0x82, 0xa0, 0x81, 0x99, 0x39, - 0xfd, 0x8f, 0x73, 0x46, 0xbf, 0xc6, 0xb9, 0x73, 0x67, 0xee, 0x9d, 0xab, 0x41, 0x1e, 0xf8, 0x71, - 0xe7, 0x7e, 0xe7, 0xf1, 0x9f, 0xb9, 0xdf, 0x7c, 0x8f, 0x99, 0x4b, 0xe4, 0xa3, 0x28, 0x4a, 0x4c, - 0x24, 0x7c, 0xfa, 0xa9, 0x2a, 0x9a, 0xe8, 0x08, 0x11, 0x25, 0x25, 0xe9, 0xdf, 0xdb, 0xe2, 0x89, - 0x7a, 0xd1, 0xe6, 0xf7, 0xeb, 0xdf, 0x07, 0x11, 0x97, 0xbe, 0x93, 0x68, 0x1f, 0x62, 0x70, 0x88, - 0x16, 0xbd, 0x7d, 0xd5, 0x10, 0x37, 0x43, 0x3a, 0x0e, 0x2c, 0x06, 0xdc, 0x16, 0x62, 0x9c, 0xa5, - 0xfc, 0x65, 0xb1, 0x60, 0x58, 0x88, 0x75, 0x99, 0x9b, 0x06, 0x2a, 0xc1, 0x1b, 0xa1, 0x52, 0xda, - 0x82, 0x19, 0xae, 0x90, 0xca, 0xc0, 0x04, 0x58, 0x02, 0x9a, 0xb0, 0x24, 0x6d, 0xa5, 0x12, 0x13, - 0xc8, 0xd8, 0x3f, 0xab, 0xe4, 0x99, 0x99, 0x95, 0xfa, 0x56, 0xe6, 0x17, 0x8d, 0x40, 0xb9, 0x06, - 0x13, 0x12, 0x6b, 0xb6, 0x4b, 0xa6, 0x73, 0x0e, 0xc4, 0x92, 0xc4, 0x9a, 0xed, 0xba, 0x83, 0x5c, - 0x83, 0x6b, 0x16, 0xf9, 0x1d, 0x2e, 0xf2, 0x3b, 0x2c, 0xf2, 0xdb, 0x5d, 0xe4, 0xb7, 0x9b, 0x72, - 0xf9, 0xfe, 0xea, 0x76, 0x91, 0xcf, 0xb1, 0x6a, 0x3f, 0x9e, 0x03, 0x5f, 0x5c, 0xe4, 0x73, 0xec, - 0x59, 0x25, 0xbf, 0x00, 0xdc, 0x02, 0x5d, 0xe0, 0x2e, 0x58, 0x00, 0xf7, 0xe5, 0x7b, 0x97, 0x1c, - 0x2f, 0x88, 0xaf, 0x4b, 0x62, 0x0b, 0x4c, 0xd7, 0xe0, 0x93, 0xcf, 0x7c, 0xf0, 0x99, 0xf4, 0x7b, - 0xc9, 0xb0, 0x52, 0x69, 0xcb, 0x37, 0xc5, 0x5a, 0x59, 0x1e, 0x98, 0x06, 0x25, 0x4a, 0x5b, 0x89, - 0xb4, 0xe5, 0xd9, 0xe4, 0x19, 0x96, 0x09, 0x9e, 0x83, 0x22, 0xa5, 0xad, 0x48, 0xda, 0x32, 0xcd, - 0xc1, 0x8b, 0x18, 0x55, 0x93, 0x71, 0x44, 0xa3, 0x51, 0x44, 0x2d, 0x3e, 0x1d, 0xa7, 0xc6, 0x79, - 0x3c, 0xcf, 0x60, 0x2a, 0xa2, 0x2c, 0x52, 0xe6, 0x99, 0x78, 0x57, 0xf3, 0x8c, 0xd9, 0x52, 0xc1, - 0x43, 0xf0, 0x40, 0x8e, 0xbd, 0xb6, 0x1c, 0xf0, 0x5e, 0xc8, 0x89, 0x40, 0xfd, 0x6c, 0xf0, 0x41, - 0xc8, 0xf6, 0xb0, 0x2e, 0x8f, 0x91, 0xbd, 0xa0, 0x0a, 0x7c, 0x15, 0xf8, 0x78, 0x0f, 0xd9, 0xcf, - 0x69, 0xc1, 0x8c, 0x7b, 0x9c, 0xbb, 0xaf, 0x0d, 0x3c, 0x05, 0xf3, 0xb4, 0x3e, 0x4e, 0xe6, 0xa5, - 0xad, 0x15, 0x1c, 0x24, 0xfb, 0xfb, 0xd6, 0xca, 0xf8, 0xbc, 0x78, 0x6c, 0x3a, 0x99, 0x17, 0xc7, - 0x25, 0xd6, 0xe9, 0xb5, 0xf0, 0xb9, 0x9c, 0x27, 0x7d, 0x5c, 0x38, 0x1d, 0xf7, 0xd3, 0x92, 0xe3, - 0xe4, 0x3a, 0xf8, 0x37, 0x79, 0xe1, 0xa2, 0xb6, 0x7a, 0x1d, 0x59, 0x41, 0x6a, 0x73, 0x5f, 0xb6, - 0x85, 0x50, 0xdb, 0xe0, 0x06, 0xd9, 0xaf, 0xc9, 0xe9, 0xa4, 0xf7, 0x5b, 0xa8, 0xf5, 0x9f, 0x48, - 0x8d, 0x40, 0x76, 0x0c, 0xfc, 0x08, 0xa3, 0x3e, 0xcf, 0xa5, 0x85, 0x36, 0xf5, 0xcf, 0x84, 0x51, - 0xdb, 0xe0, 0xb4, 0x4d, 0xfd, 0x72, 0x0f, 0xea, 0x97, 0xdb, 0xd4, 0xaf, 0xf0, 0xa0, 0x7e, 0xc5, - 0x16, 0xd6, 0x2f, 0xf3, 0xa0, 0x7e, 0xa0, 0x7d, 0x12, 0xcf, 0x57, 0x9d, 0x1e, 0xd4, 0xef, 0x94, - 0x5a, 0xaa, 0x61, 0x15, 0xa3, 0x5e, 0xf0, 0xd3, 0x83, 0xfa, 0x5c, 0xe3, 0x8e, 0xd4, 0x34, 0x8c, - 0xe7, 0x8d, 0x26, 0xf0, 0x58, 0x18, 0x03, 0xcf, 0x48, 0x5f, 0xea, 0x38, 0x67, 0x4a, 0xf1, 0x19, - 0x4c, 0x89, 0x6f, 0x46, 0x62, 0xc7, 0x14, 0x5f, 0x13, 0x6d, 0x9c, 0x8b, 0x78, 0x5c, 0xef, 0x06, - 0x29, 0xa4, 0x2f, 0xad, 0xbc, 0xc4, 0x8e, 0x80, 0x15, 0xd2, 0xe7, 0xe1, 0x64, 0xf1, 0xa5, 0xc8, - 0x71, 0xab, 0xf8, 0x46, 0x68, 0x7d, 0x39, 0x4e, 0x91, 0x1a, 0x4e, 0xf6, 0xed, 0x09, 0xa0, 0x5f, - 0x6a, 0x34, 0x58, 0xf8, 0x1b, 0xc4, 0xd7, 0x2f, 0xb1, 0x6e, 0x8d, 0x1f, 0x43, 0x06, 0xa4, 0x46, - 0xa3, 0x85, 0xbf, 0x51, 0x7c, 0x03, 0x12, 0xeb, 0xd6, 0xf8, 0x9c, 0xfa, 0xa4, 0x46, 0xbd, 0x85, - 0xbf, 0x5e, 0x7c, 0x7d, 0x14, 0xda, 0xf9, 0x73, 0xff, 0x5f, 0x01, 0x9f, 0xc0, 0x49, 0x0b, 0x3f, - 0xb7, 0x4d, 0x49, 0x4c, 0x94, 0x85, 0x7f, 0xd5, 0xb4, 0xab, 0xda, 0x2a, 0x2b, 0xd4, 0x4c, 0x8b, - 0x78, 0x94, 0x99, 0xc3, 0xa9, 0x4c, 0x52, 0xdc, 0x2a, 0xa3, 0x48, 0x63, 0x5a, 0x70, 0x2b, 0x04, - 0xc2, 0x6c, 0xdc, 0xb6, 0x98, 0x94, 0xb6, 0x06, 0x77, 0xbc, 0x9f, 0xf4, 0x89, 0x79, 0x6d, 0x1f, - 0x96, 0xb8, 0x71, 0x1f, 0x76, 0xea, 0x72, 0x51, 0x48, 0x48, 0xf9, 0x77, 0xe0, 0x2d, 0x48, 0x0b, - 0xb5, 0x4e, 0x18, 0xfa, 0xd5, 0xb4, 0x3e, 0x36, 0xab, 0xb7, 0x40, 0xbf, 0x56, 0xd1, 0xaf, 0xfd, - 0x0f, 0xf5, 0xeb, 0x14, 0xfd, 0xba, 0x4d, 0xd2, 0xe4, 0xdb, 0x9a, 0x9f, 0x35, 0x5f, 0x82, 0xdf, - 0x8a, 0x3e, 0x1f, 0xf3, 0x9e, 0x92, 0x9f, 0x23, 0x33, 0x22, 0xa0, 0xcb, 0x73, 0xe7, 0x10, 0xe9, - 0xf3, 0x46, 0xb0, 0x75, 0x82, 0x63, 0x06, 0xc1, 0x2e, 0x8f, 0xb4, 0xf3, 0x68, 0x7d, 0x3d, 0x71, - 0xc3, 0x77, 0x90, 0x1b, 0xa6, 0x76, 0x21, 0xe9, 0x7b, 0xb3, 0x50, 0xd7, 0x4c, 0xce, 0x2d, 0x08, - 0xe3, 0x37, 0x77, 0xb3, 0x97, 0x0f, 0xc4, 0x37, 0x90, 0x1c, 0x82, 0xfe, 0x90, 0x07, 0xda, 0x06, - 0x83, 0x2e, 0xb5, 0xf7, 0x9b, 0xee, 0xef, 0x70, 0xe1, 0x5a, 0x07, 0x5c, 0xe8, 0xbb, 0x79, 0x77, - 0xe3, 0x94, 0x9b, 0x2e, 0xf4, 0x5f, 0x47, 0x40, 0xff, 0x95, 0x43, 0x6d, 0xde, 0x23, 0x39, 0x19, - 0xe7, 0xa1, 0xf4, 0x41, 0xb4, 0x03, 0xfd, 0xd4, 0x08, 0x68, 0x1b, 0xa4, 0x38, 0xd0, 0xcf, 0x88, - 0xa0, 0x7e, 0xd0, 0xb9, 0x79, 0x5b, 0x7f, 0x5b, 0x7f, 0xab, 0xf4, 0x61, 0x17, 0xc1, 0xbd, 0x08, - 0xea, 0x73, 0xed, 0x0b, 0x01, 0xb4, 0xe3, 0xc1, 0xaf, 0x08, 0x6a, 0x1b, 0xf0, 0xff, 0x05, 0xf1, - 0x16, 0xfa, 0xfc, 0x50, 0x31, 0xbe, 0x09, 0xfa, 0xfc, 0x0e, 0xcd, 0x67, 0xf3, 0x1b, 0x1c, 0x02, - 0x87, 0x4d, 0xd4, 0x28, 0xf9, 0xc3, 0x16, 0x7e, 0x83, 0x61, 0x25, 0xae, 0xc6, 0xc2, 0x7f, 0xc8, - 0xea, 0xda, 0x1d, 0xdc, 0x93, 0xc5, 0x4a, 0xdd, 0x1e, 0x9b, 0xb8, 0x1e, 0x25, 0xae, 0xd8, 0xad, - 0xce, 0xb6, 0xfe, 0x3f, 0xab, 0x7f, 0x42, 0xa9, 0xdb, 0x6d, 0x13, 0xa7, 0xfe, 0x67, 0x75, 0xdc, - 0x43, 0xfd, 0x1d, 0xa4, 0xbf, 0x27, 0xe2, 0x77, 0xfc, 0x47, 0x6d, 0xe2, 0x72, 0x49, 0xdf, 0xef, - 0x3e, 0xe2, 0x1c, 0x27, 0xb5, 0xb5, 0xe5, 0x42, 0x6d, 0x03, 0x93, 0x71, 0x9a, 0xd6, 0xe2, 0xd3, - 0x70, 0x11, 0x1a, 0x36, 0x42, 0xcd, 0xcb, 0x78, 0x0e, 0x60, 0x16, 0xf1, 0x9c, 0x6f, 0x30, 0x47, - 0x94, 0x60, 0xc7, 0x24, 0x51, 0xdc, 0x28, 0x51, 0x14, 0xc3, 0xc7, 0x5a, 0xeb, 0x47, 0xcd, 0x8a, - 0x3f, 0x05, 0x2f, 0x43, 0xb9, 0xce, 0x1e, 0x00, 0x00, -}; -const StaticFile favicon_ico PROGMEM = {(sizeof(favicon_ico_content)/sizeof(favicon_ico_content[0])), favicon_ico_content}; - -} diff --git a/platformio/relayctl/src/static.h b/platformio/relayctl/src/static.h deleted file mode 100644 index 90560bf..0000000 --- a/platformio/relayctl/src/static.h +++ /dev/null @@ -1,22 +0,0 @@ -/** - * This file is autogenerated with make_static.sh script - */ - -#pragma once - -#include <stdlib.h> - -namespace homekit::files { - -typedef struct { - size_t size; - const uint8_t* content; -} StaticFile; - -extern const StaticFile index_html; -extern const StaticFile app_js; -extern const StaticFile md5_js; -extern const StaticFile style_css; -extern const StaticFile favicon_ico; - -} diff --git a/platformio/relayctl/src/wifi.cpp b/platformio/relayctl/src/wifi.cpp deleted file mode 100644 index daff7bf..0000000 --- a/platformio/relayctl/src/wifi.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include <pgmspace.h> -#include "config.def.h" -#include "wifi.h" -#include "config.h" -#include "logging.h" - -namespace homekit::wifi { - -using namespace homekit; -using homekit::config::ConfigData; - -const char HOME_ID[] = DEFAULT_HOME_ID; -const char AP_SSID[] = DEFAULT_WIFI_AP_SSID; -const char STA_SSID[] = DEFAULT_WIFI_STA_SSID; -const char STA_PSK[] = DEFAULT_WIFI_STA_PSK; - -void getConfig(ConfigData &cfg, const char** ssid, const char** psk, const char** hostname) { - if (cfg.flags.wifi_configured) { - *ssid = cfg.wifi_ssid; - *psk = cfg.wifi_psk; - *hostname = cfg.home_id; - } else { - *ssid = STA_SSID; - *psk = STA_PSK; - *hostname = HOME_ID; - } -} - -std::shared_ptr<std::list<ScanResult>> scan() { - if (WiFi.getMode() != WIFI_STA) { - PRINTLN("wifi::scan: switching mode to STA"); - WiFi.mode(WIFI_STA); - } - - std::shared_ptr<std::list<ScanResult>> results(new std::list<ScanResult>); - int count = WiFi.scanNetworks(); - for (int i = 0; i < count; i++) { - results->push_back(ScanResult { - .rssi = WiFi.RSSI(i), - .ssid = WiFi.SSID(i) - }); - } - - WiFi.scanDelete(); - return results; -} - -}
\ No newline at end of file diff --git a/platformio/relayctl/src/wifi.h b/platformio/relayctl/src/wifi.h deleted file mode 100644 index 37d8c02..0000000 --- a/platformio/relayctl/src/wifi.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include <ESP8266WiFi.h> -#include <list> -#include <memory> -#include "config.h" - -namespace homekit::wifi { - -using homekit::config::ConfigData; - -struct ScanResult { - int rssi; - String ssid; -}; - -void getConfig(ConfigData& cfg, const char** ssid, const char** psk, const char** hostname); - -std::shared_ptr<std::list<ScanResult>> scan(); - -inline uint32_t getIPAsInteger() { - if (!WiFi.isConnected()) - return 0; - return WiFi.localIP().v4(); -} - -inline int8_t getRSSI() { - return WiFi.RSSI(); -} - -extern const char AP_SSID[]; -extern const char STA_SSID[]; -extern const char STA_PSK[]; -extern const char HOME_ID[]; - -}
\ No newline at end of file diff --git a/platformio/temphum/CMakeLists.txt b/platformio/temphum/CMakeLists.txt deleted file mode 100644 index 6a8c3f1..0000000 --- a/platformio/temphum/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
-# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
-#
-# If you need to override existing CMake configuration or add extra,
-# please create `CMakeListsUser.txt` in the root of project.
-# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
-
-cmake_minimum_required(VERSION 3.13)
-set(CMAKE_SYSTEM_NAME Generic)
-set(CMAKE_C_COMPILER_WORKS 1)
-set(CMAKE_CXX_COMPILER_WORKS 1)
-
-project("temphum" C CXX)
-
-include(CMakeListsPrivate.txt)
-
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
-include(CMakeListsUser.txt)
-endif()
-
-add_custom_target(
- Production ALL
- COMMAND platformio -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-add_custom_target(
- Debug ALL
- COMMAND platformio -c clion debug "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-add_executable(Z_DUMMY_TARGET ${SRC_LIST})
diff --git a/platformio/temphum/platformio.ini b/platformio/temphum/platformio.ini deleted file mode 100644 index ad579fa..0000000 --- a/platformio/temphum/platformio.ini +++ /dev/null @@ -1,23 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:esp12e] -platform = espressif8266 -board = esp12e -framework = arduino -upload_port = /dev/ttyUSB0 -monitor_speed = 115200 -lib_deps = - https://github.com/bertmelis/espMqttClient#unordered-acks -;build_flags = -; -DDEBUG -; -DDEBUG_ESP_SSL -; -DDEBUG_ESP_PORT=Serial -build_type = release diff --git a/platformio/temphum/src/config.def.h.example b/platformio/temphum/src/config.def.h.example deleted file mode 100644 index 06c551e..0000000 --- a/platformio/temphum/src/config.def.h.example +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#define FW_VERSION 7 - -#define DEFAULT_WIFI_AP_SSID "" -#define DEFAULT_WIFI_STA_SSID "" -#define DEFAULT_WIFI_STA_PSK "" - -#define DEFAULT_MQTT_SERVER "mqtt.solarmon.ru" -#define DEFAULT_MQTT_PORT 8883 -#define DEFAULT_MQTT_USERNAME "" -#define DEFAULT_MQTT_PASSWORD "" -#define DEFAULT_MQTT_CLIENT_ID "" -#define DEFAULT_MQTT_CA_FINGERPRINT { \ - 0x0e, 0xb6, 0x3a, 0x02, 0x1f, \ - 0x4e, 0x1e, 0xe1, 0x6a, 0x67, \ - 0x62, 0xec, 0x64, 0xd4, 0x84, \ - 0x8a, 0xb0, 0xc9, 0x9c, 0xbb \ -}; - -#define DEFAULT_NODE_ID "relay-node" - -#define FLASH_BUTTON_PIN 0 -#define ESP_LED_PIN 2 -#define BOARD_LED_PIN 16 -#define RELAY_PIN 5 - -// 12 bytes string -#define HOME_SECRET_SIZE 12 -#define HOME_SECRET "" -#define MQTT_BLINK 1 - -#define ARRAY_SIZE(X) sizeof((X))/sizeof((X)[0])
\ No newline at end of file diff --git a/platformio/temphum/src/http_server.h b/platformio/temphum/src/http_server.h deleted file mode 100644 index 35f7c08..0000000 --- a/platformio/temphum/src/http_server.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include <ESP8266WebServer.h> -#include <Ticker.h> -#include <memory> -#include <list> -#include <utility> -#include "config.h" -#include "wifi.h" -#include "static.h" - -namespace homekit { - -struct OTAStatus { - bool invalidMd5; - - OTAStatus() : invalidMd5(false) {} - - inline void clean() { - invalidMd5 = false; - } -}; - -using files::StaticFile; - -class HttpServer { -private: - ESP8266WebServer server; - Ticker restartTimer; - std::shared_ptr<std::list<wifi::ScanResult>> scanResults; - OTAStatus ota; - - char* scanBuf; - size_t scanBufSize; - - void sendGzip(const StaticFile& file, PGM_P content_type); - void sendError(const String& message); - - bool getInputParam(const char* field_name, size_t max_len, String& dst); - -public: - explicit HttpServer(std::shared_ptr<std::list<wifi::ScanResult>> scanResults) - : server(80) - , scanResults(std::move(scanResults)) - , scanBufSize(512) { - scanBuf = new char[scanBufSize]; - }; - - ~HttpServer() { - delete[] scanBuf; - } - - void start(); - void loop(); -}; - -}
\ No newline at end of file diff --git a/platformio/temphum/src/led.cpp b/platformio/temphum/src/led.cpp deleted file mode 100644 index b6b0d81..0000000 --- a/platformio/temphum/src/led.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "led.h" -#include "config.def.h" - -namespace homekit { - -Led board_led(BOARD_LED_PIN); -Led esp_led(ESP_LED_PIN); - -}
\ No newline at end of file diff --git a/platformio/temphum/src/leds.cpp b/platformio/temphum/src/leds.cpp new file mode 100644 index 0000000..f0c9d51 --- /dev/null +++ b/platformio/temphum/src/leds.cpp @@ -0,0 +1,11 @@ +#include "leds.h" + +namespace homekit { + +#ifdef CONFIG_TARGET_NODEMCU +Led* board_led = new Led(CONFIG_BOARD_LED_GPIO); +#endif +Led* mcu_led = new Led(CONFIG_MCU_LED_GPIO); + +} + diff --git a/platformio/temphum/src/leds.h b/platformio/temphum/src/leds.h new file mode 100644 index 0000000..04c1f79 --- /dev/null +++ b/platformio/temphum/src/leds.h @@ -0,0 +1,15 @@ +#ifndef HOMEKIT_TEMPHUM_LEDS_H +#define HOMEKIT_TEMPHUM_LEDS_H + +#include <homekit/led.h> + +namespace homekit { + +#ifdef CONFIG_TARGET_NODEMCU +extern Led* board_led; +#endif +extern Led* mcu_led; + +} + +#endif //HOMEKIT_TEMPHUM_LEDS_H
\ No newline at end of file diff --git a/platformio/temphum/src/main.cpp b/platformio/temphum/src/main.cpp index 1fa7e66..83f35b4 100644 --- a/platformio/temphum/src/main.cpp +++ b/platformio/temphum/src/main.cpp @@ -4,42 +4,48 @@ #include <Ticker.h> #include <Wire.h> +#include <homekit/config.h> +#include <homekit/logging.h> +#ifndef CONFIG_TARGET_ESP01 +#include <homekit/http_server.h> +#endif +#include <homekit/wifi.h> + #include "mqtt.h" -#include "config.h" -#include "logging.h" -#include "http_server.h" -#include "led.h" -#include "config.def.h" -#include "wifi.h" +#include "leds.h" #include "temphum.h" -#include "stopwatch.h" using namespace homekit; +#ifndef CONFIG_TARGET_ESP01 enum class WorkingMode { RECOVERY, // AP mode, http server with configuration NORMAL, // MQTT client }; static enum WorkingMode working_mode = WorkingMode::NORMAL; +static const uint16_t recovery_boot_detection_ms = 2000; +static const uint8_t recovery_boot_delay_ms = 100; +#endif + enum class WiFiConnectionState { WAITING = 0, JUST_CONNECTED = 1, CONNECTED = 2 }; -static const uint16_t recovery_boot_detection_ms = 2000; -static const uint8_t recovery_boot_delay_ms = 100; - static volatile enum WiFiConnectionState wifi_state = WiFiConnectionState::WAITING; static void* service = nullptr; static WiFiEventHandler wifiConnectHandler, wifiDisconnectHandler; static Ticker wifiTimer; + #if MQTT_BLINK static StopWatch blinkStopWatch; #endif +#ifndef CONFIG_TARGET_ESP01 static DNSServer* dnsServer = nullptr; +#endif static void onWifiConnected(const WiFiEventStationModeGotIP& event); static void onWifiDisconnected(const WiFiEventStationModeDisconnected& event); @@ -60,8 +66,9 @@ static void wifiConnect() { PRINT("connecting to wifi.."); } +#ifndef CONFIG_TARGET_ESP01 static void wifiHotspot() { - esp_led.on(); + mcu_led->on(); auto scanResults = wifi::scan(); @@ -76,57 +83,72 @@ static void wifiHotspot() { } static void waitForRecoveryPress() { - pinMode(FLASH_BUTTON_PIN, INPUT_PULLUP); + pinMode(CONFIG_FLASH_GPIO, INPUT_PULLUP); for (uint16_t i = 0; i < recovery_boot_detection_ms; i += recovery_boot_delay_ms) { delay(recovery_boot_delay_ms); - if (digitalRead(FLASH_BUTTON_PIN) == LOW) { + if (digitalRead(CONFIG_FLASH_GPIO) == LOW) { working_mode = WorkingMode::RECOVERY; break; } } } +#endif void setup() { WiFi.disconnect(); +#ifndef CONFIG_TARGET_ESP01 waitForRecoveryPress(); - - temphum::setup(); +#endif #ifdef DEBUG Serial.begin(115200); #endif + temphum::setup(); + auto cfg = config::read(); if (config::isDirty(cfg)) { PRINTLN("config is dirty, erasing..."); config::erase(cfg); - board_led.blink(10, 50); +#ifdef CONFIG_TARGET_NODEMCU + board_led->blink(10, 50); +#else + mcu_led->blink(10, 50); +#endif } +#ifndef CONFIG_TARGET_ESP01 switch (working_mode) { case WorkingMode::RECOVERY: wifiHotspot(); break; case WorkingMode::NORMAL: +#endif wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnected); wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnected); wifiConnect(); +#ifndef CONFIG_TARGET_ESP01 break; } +#endif } void loop() { +#ifndef CONFIG_TARGET_ESP01 if (working_mode == WorkingMode::NORMAL) { +#endif if (wifi_state == WiFiConnectionState::WAITING) { PRINT("."); - esp_led.blink(2, 50); + mcu_led->blink(2, 50); delay(1000); return; } if (wifi_state == WiFiConnectionState::JUST_CONNECTED) { - board_led.blink(3, 300); +#ifdef CONFIG_TARGET_NODEMCU + board_led->blink(3, 300); +#endif wifi_state = WiFiConnectionState::CONNECTED; if (service == nullptr) @@ -144,21 +166,30 @@ void loop() { if (mqtt->ota.readyToRestart) { mqtt->disconnect(); + } else if (mqtt->diagnosticsStopWatch.elapsed(10000)) { mqtt->sendDiagnostics(); auto data = temphum::read(); + PRINT("temp:"); + PRINT(data.temp); + PRINT(", rh: "); + PRINTLN(data.rh); + mqtt->sendTempHumData(data.temp, data.rh); } #if MQTT_BLINK // periodically blink board led if (blinkStopWatch.elapsed(5000)) { - board_led.blink(1, 10); +#ifdef CONFIG_TARGET_NODEMCU + board_led->blink(1, 10); +#endif blinkStopWatch.save(); } #endif } +#ifndef CONFIG_TARGET_ESP01 } else { if (dnsServer != nullptr) dnsServer->processNextRequest(); @@ -167,6 +198,7 @@ void loop() { if (httpServer != nullptr) httpServer->loop(); } +#endif } static void onWifiConnected(const WiFiEventStationModeGotIP& event) { diff --git a/platformio/temphum/src/mqtt.cpp b/platformio/temphum/src/mqtt.cpp index ff13e43..b3305ce 100644 --- a/platformio/temphum/src/mqtt.cpp +++ b/platformio/temphum/src/mqtt.cpp @@ -1,23 +1,14 @@ #include <ESP8266httpUpdate.h> +#include <homekit/logging.h> +#include <homekit/config.h> +#include <homekit/util.h> +#include <homekit/wifi.h> + #include "mqtt.h" -#include "logging.h" -#include "wifi.h" -#include "config.def.h" -#include "config.h" -#include "static.h" -#include "util.h" -#include "led.h" +#include "leds.h" namespace homekit::mqtt { -static const uint8_t MQTT_CA_FINGERPRINT[] = DEFAULT_MQTT_CA_FINGERPRINT; -static const char MQTT_SERVER[] = DEFAULT_MQTT_SERVER; -static const uint16_t MQTT_PORT = DEFAULT_MQTT_PORT; -static const char MQTT_USERNAME[] = DEFAULT_MQTT_USERNAME; -static const char MQTT_PASSWORD[] = DEFAULT_MQTT_PASSWORD; -static const char MQTT_CLIENT_ID[] = DEFAULT_MQTT_CLIENT_ID; -static const char MQTT_SECRET[HOME_SECRET_SIZE+1] = HOME_SECRET; - static const char TOPIC_DIAGNOSTICS[] = "stat"; static const char TOPIC_INITIAL_DIAGNOSTICS[] = "stat1"; static const char TOPIC_OTA_RESPONSE[] = "otares"; @@ -168,7 +159,7 @@ void MQTT::sendInitialDiagnostics() { auto cfg = config::read(); InitialDiagnosticsPayload stat{ .ip = wifi::getIPAsInteger(), - .fw_version = FW_VERSION, + .fw_version = CONFIG_FW_VERSION, .rssi = wifi::getRSSI(), .free_heap = ESP.getFreeHeap(), .flags = DiagnosticsFlags{ @@ -224,19 +215,19 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size Update.runAsync(true); if (index == 0) { - if (length < HOME_SECRET_SIZE + MD5_SIZE) { + if (length < CONFIG_NODE_SECRET_SIZE + MD5_SIZE) { PRINTLN("mqtt/ota: failed to check secret, first packet size is too small"); return; } - if (memcmp((const char*)payload, HOME_SECRET, HOME_SECRET_SIZE) != 0) { + if (memcmp((const char*)payload, CONFIG_NODE_SECRET, CONFIG_NODE_SECRET_SIZE) != 0) { PRINTLN("mqtt/ota: invalid secret"); return; } - PRINTF("mqtt/ota: starting update, total=%ul\n", total-HOME_SECRET_SIZE); + PRINTF("mqtt/ota: starting update, total=%ul\n", total-NODE_SECRET_SIZE); for (int i = 0; i < MD5_SIZE; i++) { - md5Ptr += sprintf(md5Ptr, "%02x", *((unsigned char*)(payload+HOME_SECRET_SIZE+i))); + md5Ptr += sprintf(md5Ptr, "%02x", *((unsigned char*)(payload+CONFIG_NODE_SECRET_SIZE+i))); } md5[32] = '\0'; PRINTF("mqtt/ota: md5 is %s\n", md5); @@ -256,7 +247,7 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size ota.dataPacketId = packetId; - if (!Update.begin(total - HOME_SECRET_SIZE - MD5_SIZE)) { + if (!Update.begin(total - CONFIG_NODE_SECRET_SIZE - MD5_SIZE)) { ota.clean(); #ifdef DEBUG Update.printError(Serial); @@ -264,10 +255,10 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size sendOtaResponse(OTAResult::UPDATE_ERROR, Update.getError()); } - ota.written = Update.write(const_cast<uint8_t*>(payload)+HOME_SECRET_SIZE + MD5_SIZE, length-HOME_SECRET_SIZE - MD5_SIZE); - ota.written += HOME_SECRET_SIZE + MD5_SIZE; + ota.written = Update.write(const_cast<uint8_t*>(payload)+CONFIG_NODE_SECRET_SIZE + MD5_SIZE, length-CONFIG_NODE_SECRET_SIZE - MD5_SIZE); + ota.written += CONFIG_NODE_SECRET_SIZE + MD5_SIZE; - esp_led.blink(1, 1); + mcu_led->blink(1, 1); PRINTF("mqtt/ota: updating %u/%u\n", ota.written, Update.size()); } else { @@ -289,9 +280,9 @@ void MQTT::handleAdminOtaPayload(uint16_t packetId, const uint8_t *payload, size } ota.written += length; - esp_led.blink(1, 1); + mcu_led->blink(1, 1); PRINTF("mqtt/ota: updating %u/%u\n", - ota.written - HOME_SECRET_SIZE - MD5_SIZE, + ota.written - NODE_SECRET_SIZE - MD5_SIZE, Update.size()); } else { PRINTF("mqtt/ota: position is invalid, expected %ul, got %ul\n", ota.written, index); diff --git a/platformio/temphum/src/mqtt.h b/platformio/temphum/src/mqtt.h index 38ed988..84df5b1 100644 --- a/platformio/temphum/src/mqtt.h +++ b/platformio/temphum/src/mqtt.h @@ -1,7 +1,12 @@ +#ifndef HOMEKIT_TEMPHUM_MQTT_H +#define HOMEKIT_TEMPHUM_MQTT_H + #include <ESP8266WiFi.h> #include <espMqttClient.h> #include <Ticker.h> -#include "stopwatch.h" + +#include <homekit/stopwatch.h> +#include <homekit/mqtt.h> namespace homekit { namespace mqtt { @@ -104,4 +109,6 @@ struct OTAResponse { uint8_t error_code; } __attribute__((packed)); -} }
\ No newline at end of file +} } + +#endif //HOMEKIT_TEMPHUM_MQTT_H
\ No newline at end of file diff --git a/platformio/temphum/src/stopwatch.h b/platformio/temphum/src/stopwatch.h deleted file mode 100644 index bac2fcc..0000000 --- a/platformio/temphum/src/stopwatch.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <Arduino.h> - -namespace homekit { - -class StopWatch { -private: - unsigned long time; - -public: - StopWatch() : time(0) {}; - - inline void save() { - time = millis(); - } - - inline bool elapsed(unsigned long ms) { - unsigned long now = millis(); - if (now < time) { - // rollover? - time = now; - } else if (now - time >= ms) { - return true; - } - return false; - } -}; - -}
\ No newline at end of file diff --git a/platformio/temphum/src/temphum.cpp b/platformio/temphum/src/temphum.cpp index 0b6fbbe..9fcc2cc 100644 --- a/platformio/temphum/src/temphum.cpp +++ b/platformio/temphum/src/temphum.cpp @@ -1,16 +1,22 @@ -#include "temphum.h" -#include "logging.h" +#ifndef CONFIG_TARGET_ESP01 #include <Arduino.h> +#endif + +#include "temphum.h" namespace homekit::temphum { static const int addr = 0x40; void setup() { - pinMode(D2, OUTPUT); - pinMode(D3, OUTPUT); - - Wire.begin(D2, D3); +#ifndef CONFIG_TARGET_ESP01 + pinMode(CONFIG_SDA_GPIO, OUTPUT); + pinMode(CONFIG_SCL_GPIO, OUTPUT); + + Wire.begin(CONFIG_SDA_GPIO, CONFIG_SCL_GPIO); +#else + Wire.begin(); +#endif Wire.beginTransmission(addr); Wire.write(0xfe); diff --git a/platformio/temphum/src/util.h b/platformio/temphum/src/util.h deleted file mode 100644 index e0780d8..0000000 --- a/platformio/temphum/src/util.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -namespace homekit { - -inline size_t otaGetMaxUpdateSize() { - return (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; -} - -inline void restart() { - ESP.restart(); -} - -}
\ No newline at end of file diff --git a/src/home/mqtt/temphum.py b/src/home/mqtt/temphum.py index 83886ac..44810ef 100644 --- a/src/home/mqtt/temphum.py +++ b/src/home/mqtt/temphum.py @@ -19,6 +19,12 @@ class MqttTempHumNodes(HashableEnum): KBN_BH_1FL_BEDROOM = auto() KBN_BH_1FL_BATHROOM = auto() + KBN_NH_1FL_INV = auto() + KBN_NH_1FL_CENTER = auto() + KBN_NH_1LF_KT = auto() + KBN_NH_1FL_DS = auto() + KBN_NH_1FS_EZ = auto() + SPB_FLAT120_CABINET = auto() diff --git a/src/home/pio/__init__.py b/src/home/pio/__init__.py new file mode 100644 index 0000000..7216bc4 --- /dev/null +++ b/src/home/pio/__init__.py @@ -0,0 +1 @@ +from .products import get_products, platformio_ini
\ No newline at end of file diff --git a/src/home/pio/exceptions.py b/src/home/pio/exceptions.py new file mode 100644 index 0000000..a6afd20 --- /dev/null +++ b/src/home/pio/exceptions.py @@ -0,0 +1,2 @@ +class ProductConfigNotFoundError(Exception): + pass diff --git a/src/home/pio/products.py b/src/home/pio/products.py new file mode 100644 index 0000000..4cb3cf2 --- /dev/null +++ b/src/home/pio/products.py @@ -0,0 +1,108 @@ +import os +import logging + +from io import StringIO +from collections import OrderedDict + + +_logger = logging.getLogger(__name__) +_products_dir = os.path.join( + os.path.dirname(__file__), + '..', '..', '..', + 'platformio' +) + + +def get_products(): + products = [] + for f in os.listdir(_products_dir): + # temp hack + if f.endswith('-esp01'): + continue + # skip the common dir + if f in ('common',): + continue + + if os.path.isdir(os.path.join(_products_dir, f)): + products.append(f) + + return products + + +def platformio_ini(product_config: dict, + target: str, + node_id: str, + platform: str, + framework: str = 'arduino', + upload_port: str = '/dev/ttyUSB0', + monitor_speed: int = 115200, + debug=False, + debug_network=False) -> str: + # defines + defines = { + **product_config['common_defines'], + 'CONFIG_NODE_ID': node_id, + 'CONFIG_WIFI_AP_SSID': ('HK_'+node_id)[:31] + } + try: + defines.update(product_config['target_defines'][target]) + except KeyError: + pass + defines['CONFIG_NODE_SECRET_SIZE'] = len(defines['CONFIG_NODE_SECRET']) + defines['CONFIG_MQTT_CLIENT_ID'] = node_id + + build_type = 'release' + if debug: + defines['DEBUG'] = True + build_type = 'debug' + if debug_network: + defines['DEBUG'] = True + defines['DEBUG_ESP_SSL'] = True + defines['DEBUG_ESP_PORT'] = 'Serial' + build_type = 'debug' + defines = OrderedDict(sorted(defines.items(), key=lambda t: t[0])) + + # libs + libs = [] + if 'common_libs' in product_config: + libs.extend(product_config['common_libs']) + if 'target_libs' in product_config and target in product_config['target_libs']: + libs.extend(product_config['target_libs'][target]) + libs = list(set(libs)) + libs.sort() + + try: + target_real_name = product_config['target_board_names'][target] + except KeyError: + target_real_name = target + + buf = StringIO() + + buf.write('; Generated by pio_ini.py\n\n') + buf.write(f'[env:{target_real_name}]\n') + buf.write(f'platform = {platform}\n') + buf.write(f'board = {target_real_name}\n') + buf.write(f'framework = {framework}\n') + buf.write(f'upload_port = {upload_port}\n') + buf.write(f'monitor_speed = {monitor_speed}\n') + if libs: + buf.write(f'lib_deps =') + for lib in libs: + buf.write(f' {lib}\n') + buf.write(f'build_flags =\n') + if defines: + for name, value in defines.items(): + buf.write(f' -D{name}') + if type(value) is not bool: + buf.write('=') + if type(value) is str: + buf.write('"\\"') + value = value.replace('"', '\\"') + buf.write(f'{value}') + if type(value) is str: + buf.write('"\\"') + buf.write('\n') + buf.write(f' -I../common/include') + buf.write(f'\nbuild_type = {build_type}') + + return buf.getvalue() diff --git a/src/pio_build.py b/src/pio_build.py new file mode 100644 index 0000000..1916e5e --- /dev/null +++ b/src/pio_build.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 + +if __name__ == '__main__': + print('TODO')
\ No newline at end of file diff --git a/src/pio_ini.py b/src/pio_ini.py new file mode 100755 index 0000000..2d9c7c6 --- /dev/null +++ b/src/pio_ini.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +import os +import yaml + +from argparse import ArgumentParser, ArgumentError +from home.pio import get_products, platformio_ini +from home.pio.exceptions import ProductConfigNotFoundError + + +def get_config(product: str) -> dict: + config_path = os.path.join( + os.getenv('HOME'), '.config', + 'homekit_pio', f'{product}.yaml' + ) + if not os.path.exists(config_path): + raise ProductConfigNotFoundError(f'{config_path}: product config not found') + + with open(config_path, 'r') as f: + return yaml.safe_load(f) + + +if __name__ == '__main__': + products = get_products() + parser = ArgumentParser() + parser.add_argument('--product', type=str, choices=products, + help='PIO product name') + parser.add_argument('--target', type=str, required=True, + help='PIO build target') + parser.add_argument('--node-id', type=str) + parser.add_argument('--platform', default='espressif8266', type=str) + parser.add_argument('--framework', default='arduino', type=str) + parser.add_argument('--upload-port', default='/dev/ttyUSB0', type=str) + parser.add_argument('--monitor-speed', default=115200) + parser.add_argument('--debug', action='store_true') + parser.add_argument('--debug-network', action='store_true') + arg = parser.parse_args() + + if not arg.product: + product = os.path.basename(os.path.realpath(os.getcwd())) + if product not in products: + raise ArgumentError(None, 'invalid product') + else: + product = arg.product + + product_config = get_config(product) + if arg.target not in product_config['targets']: + raise ArgumentError(None, f'target {arg.target} not found for product {product}') + + ini = platformio_ini(product_config=product_config, + target=arg.target, + node_id=arg.node_id, + platform=arg.platform, + framework=arg.framework, + upload_port=arg.upload_port, + monitor_speed=arg.monitor_speed, + debug=arg.debug, + debug_network=arg.debug_network) + print(ini) |