aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2025-12-07 16:02:20 -0700
committerJosh Rahm <joshuarahm@gmail.com>2025-12-07 16:02:20 -0700
commit44c7f7a675d2cdb0281322f38be3227ef4fb1df2 (patch)
tree4da919b59129c1447fa9aec45e6cd51bf70dc071
parentc9efee6f3ffcf19e139d72d946aa4d837bbcbb9e (diff)
downloadesp32-ws2812b-44c7f7a675d2cdb0281322f38be3227ef4fb1df2.tar.gz
esp32-ws2812b-44c7f7a675d2cdb0281322f38be3227ef4fb1df2.tar.bz2
esp32-ws2812b-44c7f7a675d2cdb0281322f38be3227ef4fb1df2.zip
Add a "reset defaults" button and handler.
-rw-r--r--controller_webpage/index.html13
-rw-r--r--main/http_server.c33
-rw-r--r--main/main.c18
-rw-r--r--main/pattern/twinkle.c16
-rw-r--r--main/tcp_server.c9
5 files changed, 74 insertions, 15 deletions
diff --git a/controller_webpage/index.html b/controller_webpage/index.html
index bfa6461..1a308eb 100644
--- a/controller_webpage/index.html
+++ b/controller_webpage/index.html
@@ -166,6 +166,7 @@
<header>
<h1>Tree Lights Controller</h1>
<div class="toolbar">
+ <button class="secondary" onclick="resetDefaults()">Reset defaults</button>
<button class="secondary" onclick="refreshValues()">Reload</button>
</div>
</header>
@@ -341,6 +342,18 @@
}
}
+ async function resetDefaults() {
+ setStatus("Resetting…");
+ try {
+ await fetch(`${BASE_URL}/reset`, { method: "POST" });
+ await refreshValues();
+ setStatus("Reset to defaults");
+ } catch (err) {
+ setStatus("Reset failed");
+ console.error(err);
+ }
+ }
+
refreshValues();
</script>
</body>
diff --git a/main/http_server.c b/main/http_server.c
index 745bfa6..16a7256 100644
--- a/main/http_server.c
+++ b/main/http_server.c
@@ -15,14 +15,16 @@
ESP_LOGI(TAG, "Handling [%s] (%s)", #attr, req->uri); \
ws_params_t* params = (ws_params_t*)req->user_ctx; \
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); \
+ ws_state_t snapshot; \
if (xSemaphoreTake(params->state_lock, portMAX_DELAY) != pdTRUE) { \
httpd_resp_send_err( \
req, HTTPD_500_INTERNAL_SERVER_ERROR, "lock failed"); \
return ESP_FAIL; \
} \
http_handle(typ)(req, &params->state.attr); \
- ws_state_save(&params->state); \
+ snapshot = params->state; \
xSemaphoreGive(params->state_lock); \
+ ws_state_save(&snapshot); \
httpd_resp_send(req, NULL, 0); \
return ESP_OK; \
} \
@@ -92,17 +94,44 @@ static httpd_uri_t http_params_get_handler = {
.handler = handle_get_params,
.user_ctx = NULL};
+static esp_err_t handle_reset(httpd_req_t* req)
+{
+ httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+
+ ws_params_t* params = (ws_params_t*)req->user_ctx;
+ ws_state_t snapshot;
+ reset_parameters(params);
+ if (xSemaphoreTake(params->state_lock, portMAX_DELAY) != pdTRUE) {
+ httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "lock failed");
+ return ESP_FAIL;
+ }
+ snapshot = params->state;
+ xSemaphoreGive(params->state_lock);
+
+ ws_state_save(&snapshot);
+ httpd_resp_send(req, NULL, 0);
+ return ESP_OK;
+}
+
+static httpd_uri_t http_reset_handler = {
+ .uri = "/reset",
+ .method = HTTP_POST,
+ .handler = handle_reset,
+ .user_ctx = NULL};
+
httpd_handle_t start_webserver(ws_params_t* params)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.lru_purge_enable = true;
- config.max_uri_handlers = NUMBER_PARAMS + 1;
+ config.max_uri_handlers = NUMBER_PARAMS + 2;
ESP_LOGI(TAG, "Starting httpd server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) == ESP_OK) {
http_params_get_handler.user_ctx = params;
+ http_reset_handler.user_ctx = params;
httpd_register_uri_handler(server, &http_params_get_handler);
+ httpd_register_uri_handler(server, &http_reset_handler);
#define STATE_PARAM(typ, attr, ...) \
ESP_LOGI(TAG, "Registering URI handler [%s]", #attr); \
diff --git a/main/main.c b/main/main.c
index 3248b93..5f8055d 100644
--- a/main/main.c
+++ b/main/main.c
@@ -94,15 +94,15 @@ void app_main(void)
wifi_init_station("Wort", "JoshIsBau5");
ESP_LOGI("main", "Complete!");
- // if (xSemaphoreTake(ws_params.state_lock, portMAX_DELAY) == pdTRUE) {
- // esp_err_t load_err = ws_state_load(&ws_params.state);
- // if (load_err == ESP_OK) {
- // ESP_LOGI("main", "Restored state from NVS");
- // } else {
- // ESP_LOGI("main", "No saved state (%d); using defaults", load_err);
- // }
- // xSemaphoreGive(ws_params.state_lock);
- // }
+ if (xSemaphoreTake(ws_params.state_lock, portMAX_DELAY) == pdTRUE) {
+ esp_err_t load_err = ws_state_load(&ws_params.state);
+ if (load_err == ESP_OK) {
+ ESP_LOGI("main", "Restored state from NVS");
+ } else {
+ ESP_LOGI("main", "No saved state (%d); using defaults", load_err);
+ }
+ xSemaphoreGive(ws_params.state_lock);
+ }
/* Pin the LED writer to core 1 to avoid preemption by Wi-Fi/IDF tasks. */
xTaskCreatePinnedToCore(
diff --git a/main/pattern/twinkle.c b/main/pattern/twinkle.c
index d23b111..450cda6 100644
--- a/main/pattern/twinkle.c
+++ b/main/pattern/twinkle.c
@@ -1,8 +1,8 @@
+#include "pattern/twinkle.h"
+
#include <stdint.h>
#include <stdlib.h>
-#include "pattern/twinkle.h"
-
// The shape of a "spike"
uint8_t w_arr[91] = {1, 2, 4, 7, 11, 17, 24, 33, 44, 56, 70, 85,
101, 117, 134, 151, 167, 183, 197, 210, 222, 232, 240, 247,
@@ -36,7 +36,7 @@ static uint8_t pseudo_random(uint8_t x)
}
/* Produces a randomize "twinkle" effect. */
-uint8_t twinkle(uint32_t time, size_t x, uint8_t amt)
+static uint8_t twinkle_raw(uint32_t time, size_t x, uint8_t amt)
{
uint8_t time_offset = pseudo_random(x);
@@ -51,3 +51,13 @@ uint8_t twinkle(uint32_t time, size_t x, uint8_t amt)
return 0;
}
}
+
+uint8_t twinkle(uint32_t time, size_t x, uint8_t amt)
+{
+ if (time % 2 == 0) {
+ return twinkle_raw(time / 2, x, amt);
+ } else {
+ return (twinkle_raw(time / 2, x, amt) + twinkle_raw(time / 2 + 1, x, amt)) /
+ 2;
+ }
+}
diff --git a/main/tcp_server.c b/main/tcp_server.c
index 5899a36..81b97b6 100644
--- a/main/tcp_server.c
+++ b/main/tcp_server.c
@@ -25,6 +25,8 @@ static int strcmp_(const char* s1, const char* s2)
static void handle_set_cmd(
sockbuf_t* sockbuf, ws_params_t* ws_params, const char* key)
{
+ ws_state_t snapshot;
+ bool should_save = false;
if (xSemaphoreTake(ws_params->state_lock, portMAX_DELAY) != pdTRUE) {
sockbuf_write(sockbuf, "Failed to lock state\n");
return;
@@ -47,10 +49,15 @@ static void handle_set_cmd(
sockbuf_write(sockbuf, key);
sockbuf_write(sockbuf, "'\n");
} else {
- ws_state_save(&ws_params->state);
+ snapshot = ws_params->state;
+ should_save = true;
}
xSemaphoreGive(ws_params->state_lock);
+
+ if (should_save) {
+ ws_state_save(&snapshot);
+ }
}
static void handle_print_cmd(sockbuf_t* sockbuf, ws_params_t* ws_params)