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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
![]()
-
Temp.: °C
-
Heap: %
-
PSRAM: %
-
Uptime:
+
+
+
+
![]()
+
Temp.: °C
+
Heap: %
+
PSRAM: %
+
Uptime:
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
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