diff --git a/README.md b/README.md index 187faab..a4a913d 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ ## 📱 Implemented microcontrollers -- [x] Lolin S2 mini -- [ ] ESP 32 WROOM -- [ ] ESP 32 C3 +- [x] Lolin S2 mini +- [ ] ESP 32 WROOM +- [ ] ESP 32 C3 > For other microcontrollers you may need to adjust the `platformio.ini` diff --git a/components/dmx/include/dmx.h b/components/dmx/include/dmx.h index 98d095c..af80ff8 100644 --- a/components/dmx/include/dmx.h +++ b/components/dmx/include/dmx.h @@ -1,8 +1,7 @@ #pragma once #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #ifdef __cplusplus diff --git a/components/storage/include/storage.h b/components/storage/include/storage.h index 6412acb..3910ada 100644 --- a/components/storage/include/storage.h +++ b/components/storage/include/storage.h @@ -4,23 +4,22 @@ #include "esp_err.h" #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - /** - * @brief Initialize and mount LittleFS filesystem - * - * @return ESP_OK on success, error code otherwise - */ - esp_err_t storage_init(void); +/** + * @brief Initialize and mount LittleFS filesystem + * + * @return ESP_OK on success, error code otherwise + */ +esp_err_t storage_init(void); - /** - * @brief Get the mount point for the LittleFS filesystem - * - * @return Pointer to the mount point string (e.g., "/data") - */ - const char *storage_get_mount_point(void); +/** + * @brief Get the mount point for the LittleFS filesystem + * + * @return Pointer to the mount point string (e.g., "/data") + */ +const char *storage_get_mount_point(void); #ifdef __cplusplus } diff --git a/components/storage/src/storage.c b/components/storage/src/storage.c index 0602a1f..478539a 100644 --- a/components/storage/src/storage.c +++ b/components/storage/src/storage.c @@ -7,8 +7,7 @@ static const char *TAG = "STORAGE"; static const char *LITTLEFS_MOUNT_POINT = "/data"; -esp_err_t storage_init(void) -{ +esp_err_t storage_init(void) { esp_vfs_littlefs_conf_t conf = { .base_path = LITTLEFS_MOUNT_POINT, .partition_label = "storage", @@ -18,18 +17,12 @@ esp_err_t storage_init(void) esp_err_t ret = esp_vfs_littlefs_register(&conf); - if (ret != ESP_OK) - { - if (ret == ESP_FAIL) - { + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { ESP_LOGE(TAG, "Failed to mount LittleFS or format filesystem"); - } - else if (ret == ESP_ERR_INVALID_STATE) - { + } else if (ret == ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "ESP_ERR_INVALID_STATE"); - } - else - { + } else { ESP_LOGE(TAG, "Failed to initialize LittleFS: %s", esp_err_to_name(ret)); } return ret; @@ -37,20 +30,14 @@ esp_err_t storage_init(void) size_t total = 0, used = 0; ret = esp_littlefs_info(conf.partition_label, &total, &used); - if (ret == ESP_OK) - { + if (ret == ESP_OK) { ESP_LOGI(TAG, "LittleFS mounted at %s. Total: %d bytes, Used: %d bytes", LITTLEFS_MOUNT_POINT, total, used); - } - else - { + } else { ESP_LOGE(TAG, "Failed to get LittleFS information"); } return ESP_OK; } -const char *storage_get_mount_point(void) -{ - return LITTLEFS_MOUNT_POINT; -} +const char *storage_get_mount_point(void) { return LITTLEFS_MOUNT_POINT; } diff --git a/components/web_server/include/web_server.h b/components/web_server/include/web_server.h index 3ce5ccc..58a0923 100644 --- a/components/web_server/include/web_server.h +++ b/components/web_server/include/web_server.h @@ -1,6 +1,7 @@ /** * @file web_server.h - * @brief Simple HTTP web server component for ESP32 with async FreeRTOS support. + * @brief Simple HTTP web server component for ESP32 with async FreeRTOS + * support. */ #pragma once @@ -8,50 +9,50 @@ #include "esp_http_server.h" #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - /** - * @brief Web server configuration structure. - */ - typedef struct - { - uint16_t port; ///< HTTP server port (default: 80) - size_t max_uri_handlers; ///< Maximum number of URI handlers - size_t stack_size; ///< FreeRTOS task stack size - UBaseType_t task_priority; ///< FreeRTOS task priority - } webserver_config_t; +/** + * @brief Web server configuration structure. + */ +typedef struct { + uint16_t port; ///< HTTP server port (default: 80) + size_t max_uri_handlers; ///< Maximum number of URI handlers + size_t stack_size; ///< FreeRTOS task stack size + UBaseType_t task_priority; ///< FreeRTOS task priority +} webserver_config_t; - /** - * @brief Initialize and start the HTTP web server. - * - * This function creates a FreeRTOS task that manages the HTTP server. - * It serves static files from the data/ folder and supports dynamic handler registration. - * - * @param config Configuration structure. If NULL, default values are used. - * @return HTTP server handle on success, NULL on failure. - */ - httpd_handle_t webserver_start(const webserver_config_t *config); +/** + * @brief Initialize and start the HTTP web server. + * + * This function creates a FreeRTOS task that manages the HTTP server. + * It serves static files from the data/ folder and supports dynamic handler + * registration. + * + * @param config Configuration structure. If NULL, default values are used. + * @return HTTP server handle on success, NULL on failure. + */ +httpd_handle_t webserver_start(const webserver_config_t *config); - /** - * @brief Stop the web server and cleanup resources. - * - * @param server HTTP server handle returned by webserver_start(). - * Safe to pass NULL. - */ - void webserver_stop(httpd_handle_t server); +/** + * @brief Stop the web server and cleanup resources. + * + * @param server HTTP server handle returned by webserver_start(). + * Safe to pass NULL. + */ +void webserver_stop(httpd_handle_t server); - /** - * @brief Register a custom URI handler. - * - * This allows dynamic registration of API endpoints and other custom handlers. - * - * @param server HTTP server handle. - * @param uri_handler Pointer to httpd_uri_t structure. - * @return ESP_OK on success, error code otherwise. - */ - esp_err_t webserver_register_handler(httpd_handle_t server, const httpd_uri_t *uri_handler); +/** + * @brief Register a custom URI handler. + * + * This allows dynamic registration of API endpoints and other custom handlers. + * + * @param server HTTP server handle. + * @param uri_handler Pointer to httpd_uri_t structure. + * @return ESP_OK on success, error code otherwise. + */ +esp_err_t webserver_register_handler(httpd_handle_t server, + const httpd_uri_t *uri_handler); #ifdef __cplusplus } diff --git a/components/web_server/include/wifi.h b/components/web_server/include/wifi.h index c023355..4876de7 100644 --- a/components/web_server/include/wifi.h +++ b/components/web_server/include/wifi.h @@ -3,12 +3,12 @@ #include "esp_err.h" #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - esp_err_t wifi_start_ap(const char *ssid, const char *password, uint8_t channel, uint8_t max_connections); - void wifi_stop_ap(void); +esp_err_t wifi_start_ap(const char *ssid, const char *password, uint8_t channel, + uint8_t max_connections); +void wifi_stop_ap(void); #ifdef __cplusplus } diff --git a/components/web_server/src/web_server.c b/components/web_server/src/web_server.c index 19c77fd..38b050c 100644 --- a/components/web_server/src/web_server.c +++ b/components/web_server/src/web_server.c @@ -25,240 +25,219 @@ static TaskHandle_t s_server_task_handle = NULL; /** * @brief Get MIME type based on file extension */ -static const char *get_mime_type(const char *filename) -{ - const char *dot = strrchr(filename, '.'); - if (!dot) - return "application/octet-stream"; - - if (strcmp(dot, ".html") == 0) - return "text/html"; - if (strcmp(dot, ".css") == 0) - return "text/css"; - if (strcmp(dot, ".js") == 0) - return "application/javascript"; - if (strcmp(dot, ".json") == 0) - return "application/json"; - if (strcmp(dot, ".png") == 0) - return "image/png"; - if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0) - return "image/jpeg"; - if (strcmp(dot, ".gif") == 0) - return "image/gif"; - if (strcmp(dot, ".svg") == 0) - return "image/svg+xml"; - if (strcmp(dot, ".ico") == 0) - return "image/x-icon"; - if (strcmp(dot, ".txt") == 0) - return "text/plain"; - if (strcmp(dot, ".xml") == 0) - return "application/xml"; - if (strcmp(dot, ".wav") == 0) - return "audio/wav"; - if (strcmp(dot, ".mp3") == 0) - return "audio/mpeg"; - +static const char *get_mime_type(const char *filename) { + const char *dot = strrchr(filename, '.'); + if (!dot) return "application/octet-stream"; + + if (strcmp(dot, ".html") == 0) + return "text/html"; + if (strcmp(dot, ".css") == 0) + return "text/css"; + if (strcmp(dot, ".js") == 0) + return "application/javascript"; + if (strcmp(dot, ".json") == 0) + return "application/json"; + if (strcmp(dot, ".png") == 0) + return "image/png"; + if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0) + return "image/jpeg"; + if (strcmp(dot, ".gif") == 0) + return "image/gif"; + if (strcmp(dot, ".svg") == 0) + return "image/svg+xml"; + if (strcmp(dot, ".ico") == 0) + return "image/x-icon"; + if (strcmp(dot, ".txt") == 0) + return "text/plain"; + if (strcmp(dot, ".xml") == 0) + return "application/xml"; + if (strcmp(dot, ".wav") == 0) + return "audio/wav"; + if (strcmp(dot, ".mp3") == 0) + return "audio/mpeg"; + + return "application/octet-stream"; } /** * @brief HTTP handler for static files from LittleFS */ -static esp_err_t static_file_handler(httpd_req_t *req) -{ - // Build the file path - char filepath[1024]; - snprintf(filepath, sizeof(filepath), "%s%s", storage_get_mount_point(), req->uri); +static esp_err_t static_file_handler(httpd_req_t *req) { + // Build the file path + char filepath[1024]; + snprintf(filepath, sizeof(filepath), "%s%s", storage_get_mount_point(), + req->uri); - // Handle root path - if (strcmp(req->uri, "/") == 0) - { - snprintf(filepath, sizeof(filepath), "%s/index.html", storage_get_mount_point()); - } + // Handle root path + if (strcmp(req->uri, "/") == 0) { + snprintf(filepath, sizeof(filepath), "%s/index.html", + storage_get_mount_point()); + } - FILE *f = fopen(filepath, "r"); - if (!f) - { - ESP_LOGW(TAG, "File not found: %s", filepath); - httpd_resp_send_404(req); - return ESP_OK; - } - - // Get MIME type and set content type - const char *mime_type = get_mime_type(filepath); - httpd_resp_set_type(req, mime_type); - - // Send file in chunks - char buf[1024]; - size_t read_len; - while ((read_len = fread(buf, 1, sizeof(buf), f)) > 0) - { - if (httpd_resp_send_chunk(req, buf, read_len) != ESP_OK) - { - ESP_LOGW(TAG, "Failed to send data chunk for %s", filepath); - break; - } - } - - fclose(f); - httpd_resp_send_chunk(req, NULL, 0); // Send end marker + FILE *f = fopen(filepath, "r"); + if (!f) { + ESP_LOGW(TAG, "File not found: %s", filepath); + httpd_resp_send_404(req); return ESP_OK; + } + + // Get MIME type and set content type + const char *mime_type = get_mime_type(filepath); + httpd_resp_set_type(req, mime_type); + + // Send file in chunks + char buf[1024]; + size_t read_len; + while ((read_len = fread(buf, 1, sizeof(buf), f)) > 0) { + if (httpd_resp_send_chunk(req, buf, read_len) != ESP_OK) { + ESP_LOGW(TAG, "Failed to send data chunk for %s", filepath); + break; + } + } + + fclose(f); + httpd_resp_send_chunk(req, NULL, 0); // Send end marker + return ESP_OK; } /** * @brief HTTP handler for API health check (GET /api/health) */ -static esp_err_t health_check_handler(httpd_req_t *req) -{ - httpd_resp_set_type(req, "application/json"); - httpd_resp_sendstr(req, "{\"status\":\"ok\"}"); - return ESP_OK; +static esp_err_t health_check_handler(httpd_req_t *req) { + httpd_resp_set_type(req, "application/json"); + httpd_resp_sendstr(req, "{\"status\":\"ok\"}"); + return ESP_OK; } /** * @brief FreeRTOS task function for the HTTP server. * Allows non-blocking server operation and future extensibility. */ -static void webserver_task(void *arg) -{ - (void)arg; // Unused parameter - ESP_LOGI(TAG, "Web server task started"); +static void webserver_task(void *arg) { + (void)arg; // Unused parameter + ESP_LOGI(TAG, "Web server task started"); - // Keep task alive - the server runs in the background - while (s_server_handle != NULL) - { - vTaskDelay(pdMS_TO_TICKS(10000)); // 10 second check interval - } + // Keep task alive - the server runs in the background + while (s_server_handle != NULL) { + vTaskDelay(pdMS_TO_TICKS(10000)); // 10 second check interval + } - ESP_LOGI(TAG, "Web server task ending"); - vTaskDelete(NULL); + ESP_LOGI(TAG, "Web server task ending"); + vTaskDelete(NULL); } -httpd_handle_t webserver_start(const webserver_config_t *config) -{ - if (s_server_handle != NULL) - { - ESP_LOGW(TAG, "Web server already running"); - return s_server_handle; - } - - // Initialize LittleFS - esp_err_t ret = storage_init(); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to initialize storage"); - return NULL; - } - - // Use provided config or defaults - uint16_t port = WEBSERVER_DEFAULT_PORT; - size_t max_handlers = WEBSERVER_DEFAULT_MAX_HANDLERS; - size_t stack_size = WEBSERVER_DEFAULT_STACK_SIZE; - UBaseType_t task_priority = WEBSERVER_DEFAULT_TASK_PRIORITY; - - if (config) - { - port = config->port; - max_handlers = config->max_uri_handlers; - stack_size = config->stack_size; - task_priority = config->task_priority; - } - - // Create HTTP server configuration - httpd_config_t http_config = HTTPD_DEFAULT_CONFIG(); - http_config.server_port = port; - http_config.max_uri_handlers = max_handlers; - http_config.stack_size = stack_size; - http_config.uri_match_fn = httpd_uri_match_wildcard; - - // Start HTTP server - ret = httpd_start(&s_server_handle, &http_config); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(ret)); - s_server_handle = NULL; - return NULL; - } - - ESP_LOGI(TAG, "HTTP server started on port %d", port); - - // Register default handlers - // Health check endpoint - httpd_uri_t health_uri = { - .uri = "/api/health", - .method = HTTP_GET, - .handler = health_check_handler, - .user_ctx = NULL, - }; - httpd_register_uri_handler(s_server_handle, &health_uri); - - // Wildcard handler for static files from LittleFS (must be last) - httpd_uri_t file_uri = { - .uri = "/*", - .method = HTTP_GET, - .handler = static_file_handler, - .user_ctx = NULL, - }; - httpd_register_uri_handler(s_server_handle, &file_uri); - - // Create FreeRTOS task for the server - // This allows other tasks to continue running and makes the server async-ready - BaseType_t task_ret = xTaskCreate( - webserver_task, - "webserver", - stack_size, - (void *)s_server_handle, - task_priority, - &s_server_task_handle); - - if (task_ret != pdPASS) - { - ESP_LOGE(TAG, "Failed to create web server task"); - httpd_stop(s_server_handle); - s_server_handle = NULL; - return NULL; - } - - ESP_LOGI(TAG, "Web server initialized successfully"); +httpd_handle_t webserver_start(const webserver_config_t *config) { + if (s_server_handle != NULL) { + ESP_LOGW(TAG, "Web server already running"); return s_server_handle; -} + } -void webserver_stop(httpd_handle_t server) -{ - if (server == NULL) - { - return; - } + // Initialize LittleFS + esp_err_t ret = storage_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to initialize storage"); + return NULL; + } - httpd_stop(server); + // Use provided config or defaults + uint16_t port = WEBSERVER_DEFAULT_PORT; + size_t max_handlers = WEBSERVER_DEFAULT_MAX_HANDLERS; + size_t stack_size = WEBSERVER_DEFAULT_STACK_SIZE; + UBaseType_t task_priority = WEBSERVER_DEFAULT_TASK_PRIORITY; + + if (config) { + port = config->port; + max_handlers = config->max_uri_handlers; + stack_size = config->stack_size; + task_priority = config->task_priority; + } + + // Create HTTP server configuration + httpd_config_t http_config = HTTPD_DEFAULT_CONFIG(); + http_config.server_port = port; + http_config.max_uri_handlers = max_handlers; + http_config.stack_size = stack_size; + http_config.uri_match_fn = httpd_uri_match_wildcard; + + // Start HTTP server + ret = httpd_start(&s_server_handle, &http_config); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(ret)); s_server_handle = NULL; + return NULL; + } - // Wait for task to finish - if (s_server_task_handle != NULL) - { - vTaskDelay(pdMS_TO_TICKS(100)); - s_server_task_handle = NULL; - } + ESP_LOGI(TAG, "HTTP server started on port %d", port); - ESP_LOGI(TAG, "Web server stopped"); + // Register default handlers + // Health check endpoint + httpd_uri_t health_uri = { + .uri = "/api/health", + .method = HTTP_GET, + .handler = health_check_handler, + .user_ctx = NULL, + }; + httpd_register_uri_handler(s_server_handle, &health_uri); + + // Wildcard handler for static files from LittleFS (must be last) + httpd_uri_t file_uri = { + .uri = "/*", + .method = HTTP_GET, + .handler = static_file_handler, + .user_ctx = NULL, + }; + httpd_register_uri_handler(s_server_handle, &file_uri); + + // Create FreeRTOS task for the server + // This allows other tasks to continue running and makes the server + // async-ready + BaseType_t task_ret = xTaskCreate(webserver_task, "webserver", stack_size, + (void *)s_server_handle, task_priority, + &s_server_task_handle); + + if (task_ret != pdPASS) { + ESP_LOGE(TAG, "Failed to create web server task"); + httpd_stop(s_server_handle); + s_server_handle = NULL; + return NULL; + } + + ESP_LOGI(TAG, "Web server initialized successfully"); + return s_server_handle; } -esp_err_t webserver_register_handler(httpd_handle_t server, const httpd_uri_t *uri_handler) -{ - if (server == NULL || uri_handler == NULL) - { - return ESP_ERR_INVALID_ARG; - } +void webserver_stop(httpd_handle_t server) { + if (server == NULL) { + return; + } - esp_err_t ret = httpd_register_uri_handler(server, uri_handler); - if (ret == ESP_OK) - { - ESP_LOGI(TAG, "Registered handler: %s [%d]", uri_handler->uri, uri_handler->method); - } - else - { - ESP_LOGE(TAG, "Failed to register handler %s: %s", uri_handler->uri, esp_err_to_name(ret)); - } + httpd_stop(server); + s_server_handle = NULL; - return ret; + // Wait for task to finish + if (s_server_task_handle != NULL) { + vTaskDelay(pdMS_TO_TICKS(100)); + s_server_task_handle = NULL; + } + + ESP_LOGI(TAG, "Web server stopped"); +} + +esp_err_t webserver_register_handler(httpd_handle_t server, + const httpd_uri_t *uri_handler) { + if (server == NULL || uri_handler == NULL) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t ret = httpd_register_uri_handler(server, uri_handler); + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Registered handler: %s [%d]", uri_handler->uri, + uri_handler->method); + } else { + ESP_LOGE(TAG, "Failed to register handler %s: %s", uri_handler->uri, + esp_err_to_name(ret)); + } + + return ret; } diff --git a/components/web_server/src/wifi.c b/components/web_server/src/wifi.c index bff0e31..3ca0516 100644 --- a/components/web_server/src/wifi.c +++ b/components/web_server/src/wifi.c @@ -11,32 +11,28 @@ static const char *TAG = "WIFI"; static bool s_wifi_started = false; -esp_err_t wifi_start_ap(const char *ssid, const char *password, uint8_t channel, uint8_t max_connections) -{ - if (s_wifi_started) - { +esp_err_t wifi_start_ap(const char *ssid, const char *password, uint8_t channel, + uint8_t max_connections) { + if (s_wifi_started) { return ESP_OK; } - if (!ssid || strlen(ssid) == 0 || strlen(ssid) > 32) - { + if (!ssid || strlen(ssid) == 0 || strlen(ssid) > 32) { return ESP_ERR_INVALID_ARG; } const bool has_password = password && strlen(password) > 0; - if (has_password && strlen(password) < 8) - { + if (has_password && strlen(password) < 8) { return ESP_ERR_INVALID_ARG; } esp_err_t err = nvs_flash_init(); - if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) - { + if (err == ESP_ERR_NVS_NO_FREE_PAGES || + err == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } - if (err != ESP_OK) - { + if (err != ESP_OK) { return err; } @@ -48,22 +44,24 @@ esp_err_t wifi_start_ap(const char *ssid, const char *password, uint8_t channel, ESP_ERROR_CHECK(esp_wifi_init(&cfg)); wifi_config_t wifi_config = { - .ap = { - .channel = channel, - .max_connection = max_connections, - .authmode = has_password ? WIFI_AUTH_WPA2_PSK : WIFI_AUTH_OPEN, - .pmf_cfg = { - .required = false, + .ap = + { + .channel = channel, + .max_connection = max_connections, + .authmode = has_password ? WIFI_AUTH_WPA2_PSK : WIFI_AUTH_OPEN, + .pmf_cfg = + { + .required = false, + }, }, - }, }; strlcpy((char *)wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid)); wifi_config.ap.ssid_len = strlen(ssid); - if (has_password) - { - strlcpy((char *)wifi_config.ap.password, password, sizeof(wifi_config.ap.password)); + if (has_password) { + strlcpy((char *)wifi_config.ap.password, password, + sizeof(wifi_config.ap.password)); } ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); @@ -75,10 +73,8 @@ esp_err_t wifi_start_ap(const char *ssid, const char *password, uint8_t channel, return ESP_OK; } -void wifi_stop_ap(void) -{ - if (!s_wifi_started) - { +void wifi_stop_ap(void) { + if (!s_wifi_started) { return; } diff --git a/data/index.html b/data/index.html index 9859fb4..41908bb 100644 --- a/data/index.html +++ b/data/index.html @@ -1,328 +1,313 @@ - + - - - - Konfiguration - - - - - - - - - - - - -
-
-
- -

-
- -
-
+ + + + Konfiguration + + + + + + + + + + + + +
+
+
+ +

+
+ +
+
- -
- +
+ + +
+ + +
+ diff --git a/data/input-visibility.js b/data/input-visibility.js index 32445a0..6ba7466 100644 --- a/data/input-visibility.js +++ b/data/input-visibility.js @@ -4,20 +4,20 @@ const dynamicInputs = form.querySelectorAll("[data-field][data-values]"); document.addEventListener("change", updateVisibility); function updateVisibility() { - dynamicInputs.forEach((element) => { - const input = form.querySelector(`#${element.dataset.field}`); - if (element.dataset.values.split("|").includes(input.value)) { - element.classList.remove("hidden"); - element - .querySelectorAll("input, select, button, textarea") - .forEach((childInput) => (childInput.disabled = false)); - } else { - element.classList.add("hidden"); - element - .querySelectorAll("input, select, button, textarea") - .forEach((childInput) => (childInput.disabled = true)); - } - }); + dynamicInputs.forEach(element => { + const input = form.querySelector(`#${element.dataset.field}`); + if (element.dataset.values.split("|").includes(input.value)) { + element.classList.remove("hidden"); + element + .querySelectorAll("input, select, button, textarea") + .forEach(childInput => (childInput.disabled = false)); + } else { + element.classList.add("hidden"); + element + .querySelectorAll("input, select, button, textarea") + .forEach(childInput => (childInput.disabled = true)); + } + }); } updateVisibility(); diff --git a/data/load-data.js b/data/load-data.js index bf4c1e0..54c114a 100644 --- a/data/load-data.js +++ b/data/load-data.js @@ -1,7 +1,7 @@ import { - showLoadingScreen, - showError, - hideLoadingScreen, + showLoadingScreen, + showError, + hideLoadingScreen, } from "./loading-screen.js"; const form = document.querySelector("form.config"); @@ -9,46 +9,46 @@ const form = document.querySelector("form.config"); export let data = {}; export async function loadData(timeout = null) { - const req = await fetch("/config", { - method: "GET", - signal: timeout !== null ? AbortSignal.timeout(timeout) : undefined, - }); - if (!req.ok) { - throw new Error(`Response status: ${req.status}`); - } + const req = await fetch("/config", { + method: "GET", + signal: timeout !== null ? AbortSignal.timeout(timeout) : undefined, + }); + if (!req.ok) { + throw new Error(`Response status: ${req.status}`); + } - const json = await req.json(); - console.log(json); - return json; + const json = await req.json(); + console.log(json); + return json; } export function writeDataToInput(data) { - console.log("write data"); - for (const [key, value] of Object.entries(data)) { - const element = document.querySelector(`[name=${key}]`); - console.log(key, element); + console.log("write data"); + for (const [key, value] of Object.entries(data)) { + const element = document.querySelector(`[name=${key}]`); + console.log(key, element); - if (element.type === "checkbox") { - element.checked = value; - } else { - element.value = value; - } - - if (element.type === "range") { - // update text next to the slider by sending an event - element.dispatchEvent(new Event("input", { bubbles: true })); - } + if (element.type === "checkbox") { + element.checked = value; + } else { + element.value = value; } - // send "change" event - form.dispatchEvent(new Event("change", { bubbles: true })); + + if (element.type === "range") { + // update text next to the slider by sending an event + element.dispatchEvent(new Event("input", { bubbles: true })); + } + } + // send "change" event + form.dispatchEvent(new Event("change", { bubbles: true })); } showLoadingScreen("Konfiguration wird geladen..."); try { - data = await loadData(); - hideLoadingScreen(); - writeDataToInput(data); + data = await loadData(); + hideLoadingScreen(); + writeDataToInput(data); } catch (error) { - console.log(error.message); - showError("Die Konfiguration konnte nicht geladen werden."); + console.log(error.message); + showError("Die Konfiguration konnte nicht geladen werden."); } diff --git a/data/loading-screen.js b/data/loading-screen.js index 322c479..00749bf 100644 --- a/data/loading-screen.js +++ b/data/loading-screen.js @@ -5,36 +5,36 @@ const spinner = loadingScreen.querySelector(".spinner"); const reloadBtn = loadingScreen.querySelector(".reload"); export function showLoadingScreen(msg) { - hide(content, reloadBtn); - show(loadingScreen, spinner); - loadingMsg.classList.remove("error"); - loadingMsg.textContent = msg; + hide(content, reloadBtn); + show(loadingScreen, spinner); + loadingMsg.classList.remove("error"); + loadingMsg.textContent = msg; } export function showError(msg) { - showLoadingScreen(msg); - loadingMsg.innerHTML += - "
Stelle sicher, dass du mit dem DMX-Interface verbunden bist und die IP-Adresse stimmt."; - show(reloadBtn); - hide(spinner); - loadingMsg.classList.add("error"); + showLoadingScreen(msg); + loadingMsg.innerHTML += + "
Stelle sicher, dass du mit dem DMX-Interface verbunden bist und die IP-Adresse stimmt."; + show(reloadBtn); + hide(spinner); + loadingMsg.classList.add("error"); } export function hideLoadingScreen() { - hide(loadingScreen, reloadBtn); - show(content); - loadingMsg.classList.remove("error"); - loadingMsg.textContent = ""; + hide(loadingScreen, reloadBtn); + show(content); + loadingMsg.classList.remove("error"); + loadingMsg.textContent = ""; } function show(...elements) { - for (const element of elements) { - element.classList.remove("hidden"); - } + for (const element of elements) { + element.classList.remove("hidden"); + } } function hide(...elements) { - for (const element of elements) { - element.classList.add("hidden"); - } + for (const element of elements) { + element.classList.add("hidden"); + } } diff --git a/data/networks.js b/data/networks.js index 9bc4b17..8cb056e 100644 --- a/data/networks.js +++ b/data/networks.js @@ -7,67 +7,67 @@ const refreshIcon = refreshButton.querySelector("img"); let isLoading = false; refreshButton.addEventListener("click", async () => { - // check if interface is in WiFi-AccessPoint mode - if (data.connection == 1) { - alert( - "Beim WLAN-Scan wird die Verbindung hardwarebedingt kurzzeitig" + - "unterbrochen.\n" + - "Möglicherweise muss das Interface neu verbunden werden." - ); - } - updateNetworks(); + // check if interface is in WiFi-AccessPoint mode + if (data.connection == 1) { + alert( + "Beim WLAN-Scan wird die Verbindung hardwarebedingt kurzzeitig" + + "unterbrochen.\n" + + "Möglicherweise muss das Interface neu verbunden werden." + ); + } + updateNetworks(); }); // check if connected via WiFi-Station if (data.connection === 0) { - // show currently connected WiFi - insertNetworks([data.ssid]); + // show currently connected WiFi + insertNetworks([data.ssid]); } function insertNetworks(networks) { - networkDropdown.textContent = ""; // clear dropdown + networkDropdown.textContent = ""; // clear dropdown - for (const ssid of networks) { - const option = document.createElement("option"); - option.value = ssid; - option.innerText = ssid; - networkDropdown.appendChild(option); - } + for (const ssid of networks) { + const option = document.createElement("option"); + option.value = ssid; + option.innerText = ssid; + networkDropdown.appendChild(option); + } } async function loadNetworks() { - if (isLoading) return; + if (isLoading) return; - isLoading = true; - refreshButton.classList.remove("error-bg"); - refreshIcon.classList.add("spinning"); + isLoading = true; + refreshButton.classList.remove("error-bg"); + refreshIcon.classList.add("spinning"); - try { - const res = await fetch("/networks", { - method: "GET", - }); + try { + const res = await fetch("/networks", { + method: "GET", + }); - if (!res.ok) { - throw Error(`response status: ${res.status}`); - } - - const networks = await res.json(); - - refreshIcon.classList.remove("spinning"); - isLoading = false; - // remove duplicate values - return Array.from(new Set(networks)); - } catch (e) { - refreshIcon.classList.remove("spinning"); - refreshButton.classList.add("error-bg"); - isLoading = false; - return []; + if (!res.ok) { + throw Error(`response status: ${res.status}`); } + + const networks = await res.json(); + + refreshIcon.classList.remove("spinning"); + isLoading = false; + // remove duplicate values + return Array.from(new Set(networks)); + } catch (e) { + refreshIcon.classList.remove("spinning"); + refreshButton.classList.add("error-bg"); + isLoading = false; + return []; + } } async function updateNetworks() { - const networks = await loadNetworks(); - if (networks) { - insertNetworks(["", ...networks]); - } + const networks = await loadNetworks(); + if (networks) { + insertNetworks(["", ...networks]); + } } diff --git a/data/range-input.js b/data/range-input.js index 7e42f1b..cc8db68 100644 --- a/data/range-input.js +++ b/data/range-input.js @@ -1,14 +1,14 @@ -document.querySelector("form.config").addEventListener("input", (event) => { - if (event.target.classList.contains("range")) { - updateValue(event.target); - } +document.querySelector("form.config").addEventListener("input", event => { + if (event.target.classList.contains("range")) { + updateValue(event.target); + } }); function updateValue(slider) { - const percentage = Math.round((slider.value / slider.max) * 100); - slider.nextElementSibling.innerText = `${percentage}%`; + const percentage = Math.round((slider.value / slider.max) * 100); + slider.nextElementSibling.innerText = `${percentage}%`; } -document.querySelectorAll("input[type='range'].range").forEach((element) => { - updateValue(element); +document.querySelectorAll("input[type='range'].range").forEach(element => { + updateValue(element); }); diff --git a/data/reset.js b/data/reset.js index ecf29ec..8bb6354 100644 --- a/data/reset.js +++ b/data/reset.js @@ -2,15 +2,15 @@ import { updateConfig } from "/submit.js"; const form = document.querySelector("form.config"); -form.addEventListener("reset", async (event) => { - event.preventDefault(); +form.addEventListener("reset", async event => { + event.preventDefault(); - const ok = confirm( - "Sicher, dass du alle Einstellungen zurücksetzen möchtest?" - ); - if (ok) { - updateConfig({ - method: "DELETE", - }); - } + const ok = confirm( + "Sicher, dass du alle Einstellungen zurücksetzen möchtest?" + ); + if (ok) { + updateConfig({ + method: "DELETE", + }); + } }); diff --git a/data/status.js b/data/status.js index ca42350..b44c30f 100644 --- a/data/status.js +++ b/data/status.js @@ -5,108 +5,105 @@ const statusDialog = document.querySelector(".dialog-status"); const expandButton = document.querySelector(".expand-status"); expandButton.addEventListener("click", () => { - statusDialog.showModal(); + statusDialog.showModal(); }); registerCallback("status", setStatus); initWebSocket(); function setStatus(status) { - setValue("model", status.chip.model); - setValue("mac", formatMac(status.chip.mac)); - setValue("sdk-version", status.sdkVersion); + setValue("model", status.chip.model); + setValue("mac", formatMac(status.chip.mac)); + setValue("sdk-version", status.sdkVersion); - setValue("rssi", status.connection.signalStrength); - const icon = selectConnectionIcon(status.connection.signalStrength); - document.querySelectorAll(".connection-icon").forEach((img) => { - img.src = `/icons/${icon}`; - }); + setValue("rssi", status.connection.signalStrength); + const icon = selectConnectionIcon(status.connection.signalStrength); + document.querySelectorAll(".connection-icon").forEach(img => { + img.src = `/icons/${icon}`; + }); - setValue("cpu-freq", status.chip.cpuFreqMHz); - setValue("cpu-cycle-count", status.chip.cycleCount); - setValue("cpu-temp", status.chip.tempC); + setValue("cpu-freq", status.chip.cpuFreqMHz); + setValue("cpu-cycle-count", status.chip.cycleCount); + setValue("cpu-temp", status.chip.tempC); - const usedHeap = status.heap.total - status.heap.free; - setValue("heap-used", formatBytes(usedHeap)); - setValue("heap-total", formatBytes(status.heap.total)); - setValue( - "heap-percentage", - Math.round((usedHeap / status.heap.total) * 100) - ); + const usedHeap = status.heap.total - status.heap.free; + setValue("heap-used", formatBytes(usedHeap)); + setValue("heap-total", formatBytes(status.heap.total)); + setValue("heap-percentage", Math.round((usedHeap / status.heap.total) * 100)); - const usedPsram = status.psram.total - status.psram.free; - setValue("psram-used", formatBytes(usedPsram)); - setValue("psram-total", formatBytes(status.psram.total)); - setValue( - "psram-percentage", - Math.round((usedPsram / status.psram.total) * 100) - ); + const usedPsram = status.psram.total - status.psram.free; + setValue("psram-used", formatBytes(usedPsram)); + setValue("psram-total", formatBytes(status.psram.total)); + setValue( + "psram-percentage", + Math.round((usedPsram / status.psram.total) * 100) + ); - setValue("uptime", parseDuration(status.uptime)); + setValue("uptime", parseDuration(status.uptime)); - setValue("hash", parseHash(status.sketch.md5)); + setValue("hash", parseHash(status.sketch.md5)); } function setValue(className, value) { - document.querySelectorAll("." + className).forEach((element) => { - element.innerText = value; - }); + document.querySelectorAll("." + className).forEach(element => { + element.innerText = value; + }); } function parseDuration(ms) { - const date = new Date(ms); - const time = - date.getUTCHours().toString().padStart(2, "0") + - ":" + - date.getUTCMinutes().toString().padStart(2, "0") + - " h"; - const days = Math.floor(date.getTime() / (1000 * 60 * 60 * 24)); + const date = new Date(ms); + const time = + date.getUTCHours().toString().padStart(2, "0") + + ":" + + date.getUTCMinutes().toString().padStart(2, "0") + + " h"; + const days = Math.floor(date.getTime() / (1000 * 60 * 60 * 24)); - return days !== 0 ? `${days} Tage, ${time}` : time; + return days !== 0 ? `${days} Tage, ${time}` : time; } function parseHash(hash) { - return hash.toUpperCase().substring(0, 16); + return hash.toUpperCase().substring(0, 16); } function formatBytes(bytes) { - const units = ["Bytes", "KB", "MB", "GB"]; + const units = ["Bytes", "KB", "MB", "GB"]; - let value = bytes; - let index = 0; - while (value >= 1000) { - value /= 1000; - index++; - } + let value = bytes; + let index = 0; + while (value >= 1000) { + value /= 1000; + index++; + } - return `${Math.round(value * 10) / 10} ${units[index]}`; + return `${Math.round(value * 10) / 10} ${units[index]}`; } function formatMac(decimalMac) { - const octets = decimalMac.toString(16).toUpperCase().match(/../g) || []; - return octets.reverse().join(":"); + const octets = decimalMac.toString(16).toUpperCase().match(/../g) || []; + return octets.reverse().join(":"); } function selectConnectionIcon(signalStrength) { - // access point - if (data.connection == 1) { - return "hotspot.svg"; - } + // access point + if (data.connection == 1) { + return "hotspot.svg"; + } - // ethernet - if (data.connection == 2) { - return "lan.svg"; - } + // ethernet + if (data.connection == 2) { + return "lan.svg"; + } - // station - if (signalStrength >= -50) { - return "signal4.svg"; - } - if (signalStrength >= -60) { - return "signal3.svg"; - } - if (signalStrength >= -70) { - return "signal2.svg"; - } - return "signal1.svg"; + // station + if (signalStrength >= -50) { + return "signal4.svg"; + } + if (signalStrength >= -60) { + return "signal3.svg"; + } + if (signalStrength >= -70) { + return "signal2.svg"; + } + return "signal1.svg"; } diff --git a/data/style.css b/data/style.css index 06bc06e..fabefb5 100644 --- a/data/style.css +++ b/data/style.css @@ -1,330 +1,330 @@ :root { - --color-primary: #087e8b; - --color-on-primary: white; - --color-background: #222; - --color-surface: #333; - --color-danger: #fa2b58; - --appended-item-size: 2.5rem; + --color-primary: #087e8b; + --color-on-primary: white; + --color-background: #222; + --color-surface: #333; + --color-danger: #fa2b58; + --appended-item-size: 2.5rem; - color-scheme: dark; + color-scheme: dark; } body { - margin: 0; - padding: 0; - background: linear-gradient(to left, #065760, black, black, #065760); - color: white; - font-family: Arial, Helvetica, sans-serif; - overflow: hidden; + margin: 0; + padding: 0; + background: linear-gradient(to left, #065760, black, black, #065760); + color: white; + font-family: Arial, Helvetica, sans-serif; + overflow: hidden; } main { - background-color: var(--color-background); - max-width: 700px; - padding: 8px max(5%, 8px); - margin: 0 auto; - height: 100vh; - overflow: auto; + background-color: var(--color-background); + max-width: 700px; + padding: 8px max(5%, 8px); + margin: 0 auto; + height: 100vh; + overflow: auto; } h1 { - text-align: center; + text-align: center; } form > * { - margin-bottom: 16px; + margin-bottom: 16px; } fieldset { - border-radius: 8px; - border-color: white; + border-radius: 8px; + border-color: white; } label { - display: block; - display: flex; - gap: 8px; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; + display: block; + display: flex; + gap: 8px; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; } label span { - flex-grow: 1; + flex-grow: 1; } input, select, label div { - width: clamp(200px, 100%, 400px); + width: clamp(200px, 100%, 400px); } input, select { - background-color: var(--color-background); - color: white; - border: 1px solid white; - border-radius: 8px; - padding: 8px; - box-sizing: border-box; + background-color: var(--color-background); + color: white; + border: 1px solid white; + border-radius: 8px; + padding: 8px; + box-sizing: border-box; } input:focus, select:focus { - outline: none; - border-color: var(--color-primary); + outline: none; + border-color: var(--color-primary); } select:has(+ .icon-button), label div input[type="range"] { - width: calc(clamp(200px, 100%, 400px) - var(--appended-item-size) - 8px); + width: calc(clamp(200px, 100%, 400px) - var(--appended-item-size) - 8px); } input[type="range"] { - accent-color: var(--color-primary); + accent-color: var(--color-primary); } button { - border: none; - inset: none; - border-radius: 8px; - background-color: var(--color-primary); - color: var(--color-on-primary); - padding: 8px 16px; + border: none; + inset: none; + border-radius: 8px; + background-color: var(--color-primary); + color: var(--color-on-primary); + padding: 8px 16px; } button[type="reset"] { - background-color: var(--color-danger); + background-color: var(--color-danger); } :is(div:has(:is(input, select)), input, select, label) - + :is(div:has(:is(input, select)), input, select, label) { - margin-top: 8px; + + :is(div:has(:is(input, select)), input, select, label) { + margin-top: 8px; } .hidden { - display: none !important; + display: none !important; } label.switch { - display: inline-flex; - flex-direction: row; - align-items: center; - gap: 8px; - -webkit-user-select: none; - user-select: none; + display: inline-flex; + flex-direction: row; + align-items: center; + gap: 8px; + -webkit-user-select: none; + user-select: none; } label.switch input { - display: none; + display: none; } label.switch .slider { - display: inline-block; - position: relative; - height: 1em; - width: 2em; - background-color: #444; - border-radius: 1em; - border: 4px solid #444; + display: inline-block; + position: relative; + height: 1em; + width: 2em; + background-color: #444; + border-radius: 1em; + border: 4px solid #444; } label.switch .slider::before { - content: ""; - position: absolute; - height: 100%; - aspect-ratio: 1 / 1; - border-radius: 50%; - top: 50%; - background-color: white; - transition: all 0.1s linear; + content: ""; + position: absolute; + height: 100%; + aspect-ratio: 1 / 1; + border-radius: 50%; + top: 50%; + background-color: white; + transition: all 0.1s linear; } label.switch:active .slider::before { - transform: scale(1.3); - transform-origin: 50% 50%; + transform: scale(1.3); + transform-origin: 50% 50%; } label.switch input:not(:checked) + .slider::before { - left: 0%; - translate: 0 -50%; + left: 0%; + translate: 0 -50%; } label.switch input:checked + .slider::before { - left: 100%; - translate: -100% -50%; + left: 100%; + translate: -100% -50%; } dialog { - width: 80%; - max-width: 500px; - max-height: 80%; - overflow: auto; - background-color: var(--color-background); - color: white; - border: none; - border-radius: 8px; - padding: 16px; + width: 80%; + max-width: 500px; + max-height: 80%; + overflow: auto; + background-color: var(--color-background); + color: white; + border: none; + border-radius: 8px; + padding: 16px; } dialog::backdrop { - background-color: #000a; + background-color: #000a; } .dialog-header { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; - & button { - margin: 0; - } + & button { + margin: 0; + } } .card { - background-color: var(--color-surface); - padding: 8px; - border-radius: 8px; + background-color: var(--color-surface); + padding: 8px; + border-radius: 8px; } .card > * { - display: block; + display: block; } .card > :first-child { - color: var(--color-primary); - margin-bottom: 8px; + color: var(--color-primary); + margin-bottom: 8px; } .buttons { - display: flex; - flex-direction: row; - justify-content: center; - gap: 8px; + display: flex; + flex-direction: row; + justify-content: center; + gap: 8px; } .loading-screen { - display: grid; - justify-content: center; + display: grid; + justify-content: center; } .error { - color: var(--color-danger); + color: var(--color-danger); } .error-bg { - background-color: var(--color-danger) !important; + background-color: var(--color-danger) !important; } button.reload { - display: block; - margin: 0 auto; + display: block; + margin: 0 auto; } .spinner-container { - width: min(max-content, 100%); + width: min(max-content, 100%); } .spinner { - position: relative; - margin: 10px auto; - background: conic-gradient(transparent 150deg, var(--color-primary)); - --outer-diameter: 50px; - width: var(--outer-diameter); - height: var(--outer-diameter); - border-radius: 50%; + position: relative; + margin: 10px auto; + background: conic-gradient(transparent 150deg, var(--color-primary)); + --outer-diameter: 50px; + width: var(--outer-diameter); + height: var(--outer-diameter); + border-radius: 50%; - animation-name: spin; - animation-duration: 1s; - animation-iteration-count: infinite; - animation-timing-function: linear; + animation-name: spin; + animation-duration: 1s; + animation-iteration-count: infinite; + animation-timing-function: linear; } .spinner::after { - position: absolute; - content: ""; - display: block; - --spinner-border: 5px; - top: var(--spinner-border); - left: var(--spinner-border); + position: absolute; + content: ""; + display: block; + --spinner-border: 5px; + top: var(--spinner-border); + left: var(--spinner-border); - --inner-diameter: calc(var(--outer-diameter) - 2 * var(--spinner-border)); - width: var(--inner-diameter); - height: var(--inner-diameter); + --inner-diameter: calc(var(--outer-diameter) - 2 * var(--spinner-border)); + width: var(--inner-diameter); + height: var(--inner-diameter); - background-color: var(--color-background); - border-radius: 50%; + background-color: var(--color-background); + border-radius: 50%; } @keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } } .icon-button { - padding: 8px; - font-size: 0; - width: var(--appended-item-size); - height: var(--appended-item-size); + padding: 8px; + font-size: 0; + width: var(--appended-item-size); + height: var(--appended-item-size); } .spinning { - animation-name: spin; - animation-duration: 0.5s; - animation-iteration-count: infinite; - animation-timing-function: linear; + animation-name: spin; + animation-duration: 0.5s; + animation-iteration-count: infinite; + animation-timing-function: linear; } div:has(.range-value) { - display: flex; - flex-direction: row; - gap: 8px; + display: flex; + flex-direction: row; + gap: 8px; } .range-value { - width: var(--appended-item-size); - height: var(--appended-item-size); - text-align: center; - line-height: var(--appended-item-size); + width: var(--appended-item-size); + height: var(--appended-item-size); + text-align: center; + line-height: var(--appended-item-size); } .status { - background-color: var(--color-surface); - padding: 8px; - border-radius: 8px; + background-color: var(--color-surface); + padding: 8px; + border-radius: 8px; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; - gap: 16px; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + gap: 16px; } .dialog-status-content { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 8px; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; } .connection-icon { - width: 24px; - height: 24px; - padding: 8px; + width: 24px; + height: 24px; + padding: 8px; } .connection-icon.small { - padding: 0; - height: 1em; + padding: 0; + height: 1em; } .centered-vertical { - display: flex; - flex-direction: row; - align-items: center; - gap: 8px; + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; } diff --git a/data/submit.js b/data/submit.js index ee599e5..06a5fa1 100644 --- a/data/submit.js +++ b/data/submit.js @@ -1,74 +1,74 @@ import { loadData, writeDataToInput } from "./load-data.js"; import { - showLoadingScreen, - hideLoadingScreen, - showError, + showLoadingScreen, + hideLoadingScreen, + showError, } from "./loading-screen.js"; const form = document.querySelector("form.config"); function parseValue(input) { - if (input.type === "checkbox") { - return input.checked - ? input.dataset.valueChecked - : input.dataset.valueNotChecked; - } + if (input.type === "checkbox") { + return input.checked + ? input.dataset.valueChecked + : input.dataset.valueNotChecked; + } - if (input.value === "") { - return null; - } + if (input.value === "") { + return null; + } - if (input.type === "number" || input.type === "range") { - const number = Number(input.value); - return Number.isNaN(number) ? null : number; - } + if (input.type === "number" || input.type === "range") { + const number = Number(input.value); + return Number.isNaN(number) ? null : number; + } - return input.value; + return input.value; } -form.addEventListener("submit", (event) => { - event.preventDefault(); - const inputFields = document.querySelectorAll( - "form :is(input, select, textarea):not(:disabled)" - ); +form.addEventListener("submit", event => { + event.preventDefault(); + const inputFields = document.querySelectorAll( + "form :is(input, select, textarea):not(:disabled)" + ); - const data = Array.from(inputFields).reduce((data, input) => { - data[input.name] = parseValue(input); - return data; - }, {}); - console.log(data); + const data = Array.from(inputFields).reduce((data, input) => { + data[input.name] = parseValue(input); + return data; + }, {}); + console.log(data); - updateConfig({ - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(data), - }); + updateConfig({ + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(data), + }); }); export async function updateConfig(fetchOptions) { - showLoadingScreen("Konfiguration anwenden und ESP neustarten..."); + showLoadingScreen("Konfiguration anwenden und ESP neustarten..."); + try { + const res = await fetch("/config", fetchOptions); + if (!res.ok) { + throw new Error(`Response status: ${res.status}`); + } + } catch (error) { + console.error(error.message); + showError(error.message); + } + + for (let i = 0; i < 10; i++) { try { - const res = await fetch("/config", fetchOptions); - if (!res.ok) { - throw new Error(`Response status: ${res.status}`); - } + const data = await loadData(5000); + writeDataToInput(data); + hideLoadingScreen(); + + break; } catch (error) { - console.error(error.message); - showError(error.message); - } - - for (let i = 0; i < 10; i++) { - try { - const data = await loadData(5000); - writeDataToInput(data); - hideLoadingScreen(); - - break; - } catch (error) { - // retry loading config until successful - } + // retry loading config until successful } + } } diff --git a/data/websocket.js b/data/websocket.js index 268d69e..5fc3cea 100644 --- a/data/websocket.js +++ b/data/websocket.js @@ -4,34 +4,34 @@ let ws; let callbacks = {}; export function initWebSocket() { - if (ws) return; + if (ws) return; - ws = new WebSocket(gateway); + ws = new WebSocket(gateway); - ws.onopen = () => { - console.info("WebSocket connection opened"); - }; + ws.onopen = () => { + console.info("WebSocket connection opened"); + }; - ws.onclose = (event) => { - console.info("WebSocket connection closed, reason:", event.reason); - ws = null; - }; + ws.onclose = event => { + console.info("WebSocket connection closed, reason:", event.reason); + ws = null; + }; - ws.onerror = (event) => { - console.warn("WebSocket encountered error, closing socket.", event); - ws.close(); - ws = null; - }; + ws.onerror = event => { + console.warn("WebSocket encountered error, closing socket.", event); + ws.close(); + ws = null; + }; - ws.onmessage = (event) => { - const message = JSON.parse(event.data); - console.log("received websocket data", message); - if (message.type in callbacks) { - callbacks[message.type](message.data); - } - }; + ws.onmessage = event => { + const message = JSON.parse(event.data); + console.log("received websocket data", message); + if (message.type in callbacks) { + callbacks[message.type](message.data); + } + }; } export function registerCallback(type, callback) { - callbacks[type] = callback; + callbacks[type] = callback; } diff --git a/main/dmx-interface.c b/main/dmx-interface.c index 45969d1..4ed7ccd 100644 --- a/main/dmx-interface.c +++ b/main/dmx-interface.c @@ -9,21 +9,18 @@ static const char *TAG = "MAIN"; -void app_main(void) -{ +void app_main(void) { ESP_LOGI(TAG, "DMX Interface starting..."); esp_err_t wifi_err = wifi_start_ap("DMX", "mbgmbgmbg", 1, 4); - if (wifi_err != ESP_OK) - { + if (wifi_err != ESP_OK) { ESP_LOGE(TAG, "Failed to start WiFi AP: %s", esp_err_to_name(wifi_err)); return; } // Start HTTP web server httpd_handle_t server = webserver_start(NULL); - if (server == NULL) - { + if (server == NULL) { ESP_LOGE(TAG, "Failed to start web server!"); return; } @@ -32,8 +29,7 @@ void app_main(void) ESP_LOGI(TAG, "Open http://192.168.4.1 in your browser"); // Keep the app running - while (1) - { + while (1) { vTaskDelay(pdMS_TO_TICKS(1000)); } } diff --git a/main/idf_component.yml b/main/idf_component.yml index 199419b..f58a105 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -1,7 +1,7 @@ ## IDF Component Manager Manifest File dependencies: idf: - version: '>=4.1.0' + version: ">=4.1.0" joltwallet/littlefs: ==1.20.2 someweisguy/esp_dmx: git: https://github.com/davispolito/esp_dmx.git