get/post led segments
Some checks failed
ESP-IDF Build / build (esp32c6, release-v5.4) (push) Failing after 4m49s
ESP-IDF Build / build (esp32c6, release-v5.5) (push) Failing after 4m44s
ESP-IDF Build / build (esp32s3, release-v5.4) (push) Failing after 4m34s
ESP-IDF Build / build (esp32s3, release-v5.5) (push) Failing after 4m43s

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2026-01-21 21:53:03 +01:00
parent 1f02d35a97
commit df50aaedda
4 changed files with 171 additions and 16 deletions

View File

@@ -2,14 +2,17 @@
#include "common.h" #include "common.h"
#include "message_manager.h" #include "message_manager.h"
#include "led_segment.h"
#include "persistence_manager.h"
#include <cJSON.h> #include <cJSON.h>
#include <esp_http_server.h> #include <esp_http_server.h>
#include <esp_log.h> #include <esp_log.h>
#include <esp_wifi.h> #include <esp_wifi.h>
#include <persistence_manager.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#define MAX_BODY_SIZE 4096
static const char *TAG = "api_handlers"; static const char *TAG = "api_handlers";
// Helper function to set CORS headers // Helper function to set CORS headers
@@ -400,31 +403,113 @@ esp_err_t api_wled_config_get_handler(httpd_req_t *req)
{ {
ESP_LOGI(TAG, "GET /api/wled/config"); ESP_LOGI(TAG, "GET /api/wled/config");
// TODO: Implement actual LED config retrieval extern led_segment_t segments[LED_SEGMENT_MAX_LEN];
const char *response = "{" extern size_t segment_count;
"\"segments\":[" size_t required_size = sizeof(segments) * segment_count;
"{\"name\":\"Main Light\",\"start\":0,\"leds\":60},"
"{\"name\":\"Accent Light\",\"start\":60,\"leds\":30}" cJSON *json = cJSON_CreateObject();
"]"
"}"; persistence_manager_t pm;
return send_json_response(req, response); if (persistence_manager_init(&pm, "led_config") == ESP_OK)
{
persistence_manager_get_blob(&pm, "segments", segments, required_size, NULL);
uint8_t segment_count = persistence_manager_get_int(&pm, "segment_count", 0);
persistence_manager_deinit(&pm);
cJSON *segments_arr = cJSON_CreateArray();
for (uint8_t i = 0; i < segment_count; ++i)
{
cJSON *seg = cJSON_CreateObject();
cJSON_AddStringToObject(seg, "name", segments[i].name);
cJSON_AddNumberToObject(seg, "start", segments[i].start);
cJSON_AddNumberToObject(seg, "leds", segments[i].leds);
cJSON_AddItemToArray(segments_arr, seg);
}
cJSON_AddItemToObject(json, "segments", segments_arr);
}
else
{
cJSON_AddItemToObject(json, "segments", cJSON_CreateArray());
}
char *response = cJSON_PrintUnformatted(json);
cJSON_Delete(json);
esp_err_t res = send_json_response(req, response);
free(response);
return res;
} }
esp_err_t api_wled_config_post_handler(httpd_req_t *req) esp_err_t api_wled_config_post_handler(httpd_req_t *req)
{ {
ESP_LOGI(TAG, "POST /api/wled/config"); ESP_LOGI(TAG, "POST /api/wled/config");
char buf[512]; char *buf = malloc(MAX_BODY_SIZE);
int ret = httpd_req_recv(req, buf, sizeof(buf) - 1); if (!buf)
if (ret <= 0) return send_error_response(req, 500, "Memory allocation failed");
int total = 0, ret;
while (total < MAX_BODY_SIZE - 1)
{ {
return send_error_response(req, 400, "Failed to receive request body"); ret = httpd_req_recv(req, buf + total, MAX_BODY_SIZE - 1 - total);
if (ret <= 0)
break;
total += ret;
} }
buf[ret] = '\0'; buf[total] = '\0';
ESP_LOGI(TAG, "Received WLED config: %s", buf); ESP_LOGI(TAG, "Received WLED config: %s", buf);
// TODO: Parse JSON and save LED configuration cJSON *json = cJSON_Parse(buf);
free(buf);
if (!json)
{
return send_error_response(req, 400, "Invalid JSON");
}
cJSON *segments_arr = cJSON_GetObjectItem(json, "segments");
if (!cJSON_IsArray(segments_arr))
{
cJSON_Delete(json);
return send_error_response(req, 400, "Missing segments array");
}
extern led_segment_t segments[LED_SEGMENT_MAX_LEN];
extern size_t segment_count;
size_t count = cJSON_GetArraySize(segments_arr);
if (count > LED_SEGMENT_MAX_LEN)
count = LED_SEGMENT_MAX_LEN;
segment_count = count;
for (size_t i = 0; i < LED_SEGMENT_MAX_LEN; ++i)
{
cJSON *seg = cJSON_GetArrayItem(segments_arr, i);
cJSON *name = cJSON_GetObjectItem(seg, "name");
cJSON *start = cJSON_GetObjectItem(seg, "start");
cJSON *leds = cJSON_GetObjectItem(seg, "leds");
if (cJSON_IsString(name) && cJSON_IsNumber(start) && cJSON_IsNumber(leds) && i < count)
{
strncpy(segments[i].name, name->valuestring, sizeof(segments[i].name) - 1);
segments[i].name[sizeof(segments[i].name) - 1] = '\0';
segments[i].start = (uint16_t)start->valuedouble;
segments[i].leds = (uint16_t)leds->valuedouble;
}
else
{
// Invalid entry, skip or set defaults
segments[i].name[0] = '\0';
segments[i].start = 0;
segments[i].leds = 0;
}
}
cJSON_Delete(json);
persistence_manager_t pm;
if (persistence_manager_init(&pm, "led_config") == ESP_OK)
{
persistence_manager_set_blob(&pm, "segments", segments, sizeof(led_segment_t) * segment_count);
persistence_manager_set_int(&pm, "segment_count", (int32_t)segment_count);
persistence_manager_deinit(&pm);
}
set_cors_headers(req); set_cors_headers(req);
return httpd_resp_sendstr(req, "{\"status\":\"ok\"}"); return httpd_resp_sendstr(req, "{\"status\":\"ok\"}");
} }

View File

@@ -0,0 +1,16 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#define LED_SEGMENT_MAX_LEN 15
typedef struct
{
char name[32];
uint16_t start;
uint16_t leds;
} led_segment_t;
led_segment_t segments[LED_SEGMENT_MAX_LEN];
size_t segment_count;

View File

@@ -205,6 +205,33 @@ extern "C"
void persistence_manager_get_string(const persistence_manager_t *pm, const char *key, char *out_value, void persistence_manager_get_string(const persistence_manager_t *pm, const char *key, char *out_value,
size_t max_len, const char *default_value); size_t max_len, const char *default_value);
/**
* @brief Set a blob (binary data) value for a key in NVS storage.
*
* This function stores arbitrary binary data under the given key.
*
* @param pm Pointer to the persistence manager structure.
* @param key Key to set.
* @param value Pointer to the data to store.
* @param length Length of the data in bytes.
*/
void persistence_manager_set_blob(persistence_manager_t *pm, const char *key, const void *value, size_t length);
/**
* @brief Get a blob (binary data) value for a key from NVS storage.
*
* This function retrieves binary data previously stored under the given key.
*
* @param pm Pointer to the persistence manager structure.
* @param key Key to retrieve.
* @param out_value Buffer to store the retrieved data.
* @param max_length Maximum length of the output buffer in bytes.
* @param out_length Pointer to variable to receive the actual data length.
* @return true if the blob was found and read successfully, false otherwise.
*/
bool persistence_manager_get_blob(const persistence_manager_t *pm, const char *key, void *out_value,
size_t max_length, size_t *out_length);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,4 +1,3 @@
#include "persistence_manager.h" #include "persistence_manager.h"
#include <esp_log.h> #include <esp_log.h>
#include <string.h> #include <string.h>
@@ -174,6 +173,17 @@ void persistence_manager_set_string(persistence_manager_t *pm, const char *key,
} }
} }
void persistence_manager_set_blob(persistence_manager_t *pm, const char *key, const void *value, size_t length)
{
if (!persistence_manager_is_initialized(pm) || !value || length == 0)
return;
esp_err_t err = nvs_set_blob(pm->nvs_handle, key, value, length);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to set blob key '%s': %s", key, esp_err_to_name(err));
}
}
bool persistence_manager_get_bool(const persistence_manager_t *pm, const char *key, bool default_value) bool persistence_manager_get_bool(const persistence_manager_t *pm, const char *key, bool default_value)
{ {
if (!persistence_manager_is_initialized(pm)) if (!persistence_manager_is_initialized(pm))
@@ -245,3 +255,20 @@ void persistence_manager_get_string(const persistence_manager_t *pm, const char
return; return;
} }
} }
bool persistence_manager_get_blob(const persistence_manager_t *pm, const char *key, void *out_value, size_t max_length,
size_t *out_length)
{
if (!persistence_manager_is_initialized(pm) || !out_value || max_length == 0)
return false;
size_t required_size = 0;
esp_err_t err = nvs_get_blob(pm->nvs_handle, key, NULL, &required_size);
if (err != ESP_OK || required_size == 0 || required_size > max_length)
return false;
err = nvs_get_blob(pm->nvs_handle, key, out_value, &required_size);
if (err != ESP_OK)
return false;
if (out_length)
*out_length = required_size;
return true;
}