edit of all config data via website

Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
2026-01-25 00:14:52 +01:00
parent df50aaedda
commit c28d7d08df
24 changed files with 1790 additions and 2967 deletions

View File

@@ -2,8 +2,10 @@
#include "common.h"
#include "message_manager.h"
#include "esp_heap_caps.h"
#include "led_segment.h"
#include "persistence_manager.h"
#include "storage.h"
#include <cJSON.h>
#include <esp_http_server.h>
#include <esp_log.h>
@@ -93,7 +95,7 @@ esp_err_t api_wifi_scan_handler(httpd_req_t *req)
uint16_t ap_num = 0;
esp_wifi_scan_get_ap_num(&ap_num);
wifi_ap_record_t *ap_list = calloc(ap_num, sizeof(wifi_ap_record_t));
wifi_ap_record_t *ap_list = heap_caps_calloc(ap_num, sizeof(wifi_ap_record_t), MALLOC_CAP_SPIRAM);
if (!ap_list)
{
return send_error_response(req, 500, "Memory allocation failed");
@@ -162,7 +164,7 @@ esp_err_t api_wifi_config_handler(httpd_req_t *req)
if (is_valid(pw))
{
size_t pwlen = strlen(pw->valuestring);
char *masked = malloc(pwlen + 1);
char *masked = heap_caps_malloc(pwlen + 1, MALLOC_CAP_SPIRAM);
if (masked)
{
memset(masked, '*', pwlen);
@@ -443,7 +445,7 @@ esp_err_t api_wled_config_post_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "POST /api/wled/config");
char *buf = malloc(MAX_BODY_SIZE);
char *buf = heap_caps_malloc(MAX_BODY_SIZE, MALLOC_CAP_SPIRAM);
if (!buf)
return send_error_response(req, 500, "Memory allocation failed");
int total = 0, ret;
@@ -517,6 +519,16 @@ esp_err_t api_wled_config_post_handler(httpd_req_t *req)
// ============================================================================
// Schema API
// ============================================================================
static char *heap_caps_strdup(const char *src, uint32_t caps)
{
if (!src)
return NULL;
size_t len = strlen(src) + 1;
char *dst = heap_caps_malloc(len, caps);
if (dst)
memcpy(dst, src, len);
return dst;
}
esp_err_t api_schema_get_handler(httpd_req_t *req)
{
@@ -538,8 +550,6 @@ esp_err_t api_schema_get_handler(httpd_req_t *req)
snprintf(path, sizeof(path), "%s", filename);
int line_count = 0;
extern char **read_lines_filtered(const char *filename, int *out_count);
extern void free_lines(char **lines, int count);
char **lines = read_lines_filtered(path, &line_count);
set_cors_headers(req);
@@ -554,7 +564,7 @@ esp_err_t api_schema_get_handler(httpd_req_t *req)
size_t total_len = 0;
for (int i = 0; i < line_count; ++i)
total_len += strlen(lines[i]) + 1;
char *csv = malloc(total_len + 1);
char *csv = heap_caps_malloc(total_len + 1, MALLOC_CAP_SPIRAM);
char *p = csv;
for (int i = 0; i < line_count; ++i)
{
@@ -575,26 +585,75 @@ esp_err_t api_schema_post_handler(httpd_req_t *req)
ESP_LOGI(TAG, "POST /api/schema/*");
// Extract filename from URI
const char *uri = req->uri;
const char *filename = strrchr(uri, '/');
if (filename == NULL)
if (!req)
{
ESP_LOGE(TAG, "Request pointer is NULL");
return send_error_response(req, 500, "Internal error: req is NULL");
}
const char *uri = req->uri;
ESP_LOGI(TAG, "Request URI: %s", uri ? uri : "(null)");
if (!uri)
{
ESP_LOGE(TAG, "Request URI is NULL");
return send_error_response(req, 400, "Invalid schema path (no URI)");
}
const char *filename = strrchr(uri, '/');
if (filename == NULL || filename[1] == '\0')
{
ESP_LOGE(TAG, "Could not extract filename from URI: %s", uri);
return send_error_response(req, 400, "Invalid schema path");
}
filename++;
ESP_LOGI(TAG, "Extracted filename: %s", filename);
char buf[2048];
int ret = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (ret <= 0)
// Dynamically read POST body (like api_wled_config_post_handler)
char *buf = heap_caps_malloc(MAX_BODY_SIZE, MALLOC_CAP_SPIRAM);
if (!buf)
{
return send_error_response(req, 400, "Failed to receive request body");
ESP_LOGE(TAG, "Memory allocation failed for POST body");
return send_error_response(req, 500, "Memory allocation failed");
}
buf[ret] = '\0';
int total = 0, ret;
while (total < MAX_BODY_SIZE - 1)
{
ret = httpd_req_recv(req, buf + total, MAX_BODY_SIZE - 1 - total);
if (ret <= 0)
break;
total += ret;
}
buf[total] = '\0';
ESP_LOGI(TAG, "Saving schema %s, size: %d bytes", filename, ret);
ESP_LOGI(TAG, "Saving schema %s, size: %d bytes", filename, total);
// TODO: Save schema to storage
// Split CSV body into line array
int line_count = 0;
// Count lines
for (int i = 0; i < total; ++i)
if (buf[i] == '\n')
line_count++;
if (total > 0 && buf[total - 1] != '\n')
line_count++; // last line without \n
char **lines = (char **)heap_caps_malloc(line_count * sizeof(char *), MALLOC_CAP_SPIRAM);
int idx = 0;
char *saveptr = NULL;
char *line = strtok_r(buf, "\n", &saveptr);
while (line && idx < line_count)
{
// Ignore empty lines
if (line[0] != '\0')
lines[idx++] = heap_caps_strdup(line, MALLOC_CAP_SPIRAM);
line = strtok_r(NULL, "\n", &saveptr);
}
int actual_count = idx;
esp_err_t err = write_lines(filename, lines, actual_count);
for (int i = 0; i < actual_count; ++i)
free(lines[i]);
free(lines);
set_cors_headers(req);
if (err != ESP_OK)
return send_error_response(req, 500, "Failed to save schema");
return httpd_resp_sendstr(req, "{\"status\":\"ok\"}");
}

View File

@@ -1,5 +1,7 @@
#pragma once
#include "esp_err.h"
#ifdef __cplusplus
extern "C"
{
@@ -8,6 +10,14 @@ extern "C"
void load_file(const char *filename);
char **read_lines_filtered(const char *filename, int *out_count);
void free_lines(char **lines, int count);
/**
* Write an array of lines to a file (CSV or other text).
* @param filename File name (without /spiffs/)
* @param lines Array of lines (null-terminated strings)
* @param count Number of lines
* @return ESP_OK on success, error code otherwise
*/
esp_err_t write_lines(const char *filename, char **lines, int count);
#ifdef __cplusplus
}
#endif

View File

@@ -130,3 +130,27 @@ void free_lines(char **lines, int count)
free(lines[i]);
free(lines);
}
esp_err_t write_lines(const char *filename, char **lines, int count)
{
char fullpath[128];
snprintf(fullpath, sizeof(fullpath), "/spiffs/%s", filename[0] == '/' ? filename + 1 : filename);
FILE *f = fopen(fullpath, "w");
if (!f)
{
ESP_LOGE(TAG, "Failed to open file for writing: %s", fullpath);
return ESP_FAIL;
}
for (int i = 0; i < count; ++i)
{
if (fprintf(f, "%s\n", lines[i]) < 0)
{
ESP_LOGE(TAG, "Failed to write line %d", i);
fclose(f);
return ESP_FAIL;
}
}
fclose(f);
ESP_LOGI(TAG, "Wrote %d lines to %s", count, fullpath);
return ESP_OK;
}