Compare commits
3 Commits
ccdc2bb63f
...
dc40acfd06
| Author | SHA1 | Date | |
|---|---|---|---|
|
dc40acfd06
|
|||
|
3d7de05614
|
|||
|
3f32b791b7
|
@@ -309,7 +309,37 @@ esp_err_t api_light_mode_handler(httpd_req_t *req)
|
||||
|
||||
ESP_LOGI(TAG, "Received light mode: %s", buf);
|
||||
|
||||
// TODO: Parse JSON and set light mode
|
||||
cJSON *json = cJSON_Parse(buf);
|
||||
if (json)
|
||||
{
|
||||
cJSON *mode = cJSON_GetObjectItem(json, "mode");
|
||||
if (cJSON_IsString(mode))
|
||||
{
|
||||
message_t msg = {};
|
||||
msg.type = MESSAGE_TYPE_SETTINGS;
|
||||
msg.data.settings.type = SETTINGS_TYPE_INT;
|
||||
strncpy(msg.data.settings.key, "light_mode", sizeof(msg.data.settings.key) - 1);
|
||||
if (strcmp(mode->valuestring, "simulation") == 0)
|
||||
{
|
||||
msg.data.settings.value.int_value = 0;
|
||||
}
|
||||
else if (strcmp(mode->valuestring, "day") == 0)
|
||||
{
|
||||
msg.data.settings.value.int_value = 1;
|
||||
}
|
||||
else if (strcmp(mode->valuestring, "night") == 0)
|
||||
{
|
||||
msg.data.settings.value.int_value = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.data.settings.value.int_value = -1; // Unbekannter Modus
|
||||
}
|
||||
message_manager_post(&msg, pdMS_TO_TICKS(100));
|
||||
}
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
|
||||
set_cors_headers(req);
|
||||
return httpd_resp_sendstr(req, "{\"status\":\"ok\"}");
|
||||
}
|
||||
@@ -328,7 +358,25 @@ esp_err_t api_light_schema_handler(httpd_req_t *req)
|
||||
|
||||
ESP_LOGI(TAG, "Received schema setting: %s", buf);
|
||||
|
||||
// TODO: Parse JSON and set active schema
|
||||
cJSON *json = cJSON_Parse(buf);
|
||||
if (json)
|
||||
{
|
||||
cJSON *schema_file = cJSON_GetObjectItem(json, "schema");
|
||||
if (cJSON_IsString(schema_file))
|
||||
{
|
||||
int schema_id = 0;
|
||||
sscanf(schema_file->valuestring, "schema_%d.csv", &schema_id);
|
||||
|
||||
message_t msg = {};
|
||||
msg.type = MESSAGE_TYPE_SETTINGS;
|
||||
msg.data.settings.type = SETTINGS_TYPE_INT;
|
||||
strncpy(msg.data.settings.key, "light_variant", sizeof(msg.data.settings.key) - 1);
|
||||
msg.data.settings.value.int_value = schema_id;
|
||||
message_manager_post(&msg, pdMS_TO_TICKS(100));
|
||||
}
|
||||
cJSON_Delete(json);
|
||||
}
|
||||
|
||||
set_cors_headers(req);
|
||||
return httpd_resp_sendstr(req, "{\"status\":\"ok\"}");
|
||||
}
|
||||
@@ -400,14 +448,41 @@ esp_err_t api_schema_get_handler(httpd_req_t *req)
|
||||
|
||||
ESP_LOGI(TAG, "Requested schema: %s", filename);
|
||||
|
||||
// TODO: Read actual schema file from storage
|
||||
// For now, return sample CSV data
|
||||
// Schema-Datei lesen
|
||||
char path[128];
|
||||
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);
|
||||
httpd_resp_set_type(req, "text/csv");
|
||||
const char *sample_csv = "255,240,220,0,100,250\n"
|
||||
"255,230,200,0,120,250\n"
|
||||
"255,220,180,0,140,250\n";
|
||||
return httpd_resp_sendstr(req, sample_csv);
|
||||
|
||||
if (!lines || line_count == 0)
|
||||
{
|
||||
return httpd_resp_sendstr(req, "");
|
||||
}
|
||||
|
||||
// Gesamtlänge berechnen
|
||||
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 *p = csv;
|
||||
for (int i = 0; i < line_count; ++i)
|
||||
{
|
||||
size_t l = strlen(lines[i]);
|
||||
memcpy(p, lines[i], l);
|
||||
p += l;
|
||||
*p++ = '\n';
|
||||
}
|
||||
*p = '\0';
|
||||
free_lines(lines, line_count);
|
||||
esp_err_t res = httpd_resp_sendstr(req, csv);
|
||||
free(csv);
|
||||
return res;
|
||||
}
|
||||
|
||||
esp_err_t api_schema_post_handler(httpd_req_t *req)
|
||||
|
||||
@@ -13,8 +13,21 @@ cJSON *create_light_status_json(void)
|
||||
|
||||
bool light_active = persistence_manager_get_bool(&pm, "light_active", false);
|
||||
cJSON_AddBoolToObject(json, "on", light_active);
|
||||
|
||||
cJSON_AddBoolToObject(json, "thunder", false);
|
||||
cJSON_AddStringToObject(json, "mode", "day");
|
||||
|
||||
int mode = persistence_manager_get_int(&pm, "light_mode", 0);
|
||||
const char *mode_str = "simulation";
|
||||
if (mode == 1)
|
||||
{
|
||||
mode_str = "day";
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
mode_str = "night";
|
||||
}
|
||||
cJSON_AddStringToObject(json, "mode", mode_str);
|
||||
|
||||
cJSON_AddStringToObject(json, "schema", "schema_03.csv");
|
||||
cJSON *color = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(color, "r", 255);
|
||||
|
||||
@@ -10,6 +10,7 @@ idf_component_register(SRCS
|
||||
driver
|
||||
nvs_flash
|
||||
esp_insights
|
||||
analytics
|
||||
led-manager
|
||||
api-server
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "wifi_manager.h"
|
||||
#include "dns_hijack.h"
|
||||
|
||||
#include "analytics.h"
|
||||
#include "api_server.h"
|
||||
|
||||
#include <esp_event.h>
|
||||
#include <esp_insights.h>
|
||||
#include <esp_log.h>
|
||||
@@ -59,6 +59,7 @@ static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t e
|
||||
{
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
ESP_LOGI(TAG, "IP_EVENT_STA_GOT_IP: IP-Adresse erhalten: " IPSTR, IP2STR(&event->ip_info.ip));
|
||||
analytics_init();
|
||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||
}
|
||||
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_LOST_IP)
|
||||
|
||||
@@ -206,6 +206,8 @@ class Menu : public Widget
|
||||
*/
|
||||
MenuItem switchValue(const MenuItem &menuItem, ButtonType button);
|
||||
|
||||
void setSelectionIndex(const MenuItem &menuItem, int index);
|
||||
|
||||
private:
|
||||
MenuItem replaceItem(int index, const MenuItem &item);
|
||||
|
||||
|
||||
@@ -126,6 +126,15 @@ MenuItem Menu::switchValue(const MenuItem &menuItem, ButtonType button)
|
||||
return result;
|
||||
}
|
||||
|
||||
void Menu::setSelectionIndex(const MenuItem &menuItem, int index)
|
||||
{
|
||||
if (index >= 0 && index < menuItem.getItemCount())
|
||||
{
|
||||
auto item = menuItem.copyWith(index);
|
||||
replaceItem(menuItem.getId(), item);
|
||||
}
|
||||
}
|
||||
|
||||
MenuItem Menu::replaceItem(const int index, const MenuItem &item)
|
||||
{
|
||||
m_items.at(index) = item;
|
||||
|
||||
@@ -91,11 +91,14 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
|
||||
const auto value = getItem(item.getId()).getIndex();
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
persistence_manager_set_int(m_options->persistenceManager, LightMenuOptions::LIGHT_MODE, value);
|
||||
persistence_manager_save(m_options->persistenceManager);
|
||||
// Post change via message_manager
|
||||
message_t msg = {};
|
||||
msg.type = MESSAGE_TYPE_SETTINGS;
|
||||
msg.data.settings.type = SETTINGS_TYPE_INT;
|
||||
strncpy(msg.data.settings.key, LightMenuOptions::LIGHT_MODE, sizeof(msg.data.settings.key) - 1);
|
||||
msg.data.settings.value.int_value = value;
|
||||
message_manager_post(&msg, pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
start_simulation();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -108,11 +111,14 @@ void LightMenu::onButtonPressed(const MenuItem &menuItem, const ButtonType butto
|
||||
const auto value = getItem(item.getId()).getIndex() + 1;
|
||||
if (m_options && m_options->persistenceManager)
|
||||
{
|
||||
persistence_manager_set_int(m_options->persistenceManager, LightMenuOptions::LIGHT_VARIANT, value);
|
||||
persistence_manager_save(m_options->persistenceManager);
|
||||
// Post change via message_manager
|
||||
message_t msg = {};
|
||||
msg.type = MESSAGE_TYPE_SETTINGS;
|
||||
msg.data.settings.type = SETTINGS_TYPE_INT;
|
||||
strncpy(msg.data.settings.key, LightMenuOptions::LIGHT_VARIANT, sizeof(msg.data.settings.key) - 1);
|
||||
msg.data.settings.value.int_value = value;
|
||||
message_manager_post(&msg, pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
start_simulation();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -133,10 +139,20 @@ void LightMenu::onMessageReceived(const message_t *msg)
|
||||
{
|
||||
// Here you can react to messages, e.g. set toggle status
|
||||
// Example: If light_active was changed, synchronize toggle
|
||||
if (msg && msg->type == MESSAGE_TYPE_SETTINGS && msg->data.settings.type == SETTINGS_TYPE_BOOL &&
|
||||
std::strcmp(msg->data.settings.key, "light_active") == 0)
|
||||
if (msg && msg->type == MESSAGE_TYPE_SETTINGS)
|
||||
{
|
||||
setToggle(getItem(LightMenuItem::ACTIVATE), msg->data.settings.value.bool_value);
|
||||
if (std::strcmp(msg->data.settings.key, LightMenuOptions::LIGHT_ACTIVE) == 0)
|
||||
{
|
||||
setToggle(getItem(LightMenuItem::ACTIVATE), msg->data.settings.value.bool_value);
|
||||
}
|
||||
if (std::strcmp(msg->data.settings.key, LightMenuOptions::LIGHT_MODE) == 0)
|
||||
{
|
||||
setSelectionIndex(getItem(LightMenuItem::MODE), msg->data.settings.value.int_value);
|
||||
}
|
||||
if (std::strcmp(msg->data.settings.key, LightMenuOptions::LIGHT_VARIANT) == 0)
|
||||
{
|
||||
setSelectionIndex(getItem(LightMenuItem::VARIANT), msg->data.settings.value.int_value - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ extern "C"
|
||||
#endif
|
||||
void initialize_storage();
|
||||
void load_file(const char *filename);
|
||||
char **read_lines_filtered(const char *filename, int *out_count);
|
||||
void free_lines(char **lines, int count);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -148,7 +148,7 @@ static void initialize_light_items(void)
|
||||
persistence_manager_t persistence;
|
||||
persistence_manager_init(&persistence, "config");
|
||||
int variant = persistence_manager_get_int(&persistence, "light_variant", 1);
|
||||
snprintf(filename, sizeof(filename), "/spiffs/schema_%02d.csv", variant);
|
||||
snprintf(filename, sizeof(filename), "schema_%02d.csv", variant);
|
||||
load_file(filename);
|
||||
persistence_manager_deinit(&persistence);
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "simulator.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "storage";
|
||||
|
||||
@@ -49,59 +51,82 @@ void initialize_storage()
|
||||
void load_file(const char *filename)
|
||||
{
|
||||
ESP_LOGI(TAG, "Loading file: %s", filename);
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (f == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open file for reading");
|
||||
return;
|
||||
}
|
||||
|
||||
char line[128];
|
||||
int line_count = 0;
|
||||
char **lines = read_lines_filtered(filename, &line_count);
|
||||
uint8_t line_number = 0;
|
||||
while (fgets(line, sizeof(line), f))
|
||||
for (int i = 0; i < line_count; ++i)
|
||||
{
|
||||
char *pos = strchr(line, '\n');
|
||||
if (pos)
|
||||
{
|
||||
*pos = '\0';
|
||||
}
|
||||
|
||||
if (strlen(line) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char *trimmed = line;
|
||||
while (*trimmed == ' ' || *trimmed == '\t')
|
||||
{
|
||||
trimmed++;
|
||||
}
|
||||
if (*trimmed == '#' || *trimmed == '\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
char time[10] = {0};
|
||||
int red, green, blue, white, brightness, saturation;
|
||||
|
||||
int items_scanned = sscanf(line, "%d,%d,%d,%d,%d,%d", &red, &green, &blue, &white, &brightness, &saturation);
|
||||
int items_scanned =
|
||||
sscanf(lines[i], "%d,%d,%d,%d,%d,%d", &red, &green, &blue, &white, &brightness, &saturation);
|
||||
if (items_scanned == 6)
|
||||
{
|
||||
int total_minutes = line_number * 30;
|
||||
int hours = total_minutes / 60;
|
||||
int minutes = total_minutes % 60;
|
||||
|
||||
snprintf(time, sizeof(time), "%02d%02d", hours, minutes);
|
||||
|
||||
add_light_item(time, red, green, blue, white, brightness, saturation);
|
||||
line_number++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Could not parse line: %s", line);
|
||||
ESP_LOGW(TAG, "Could not parse line: %s", lines[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
free_lines(lines, line_count);
|
||||
ESP_LOGI(TAG, "Finished loading file. Loaded %d entries.", line_number);
|
||||
}
|
||||
|
||||
char **read_lines_filtered(const char *filename, int *out_count)
|
||||
{
|
||||
char fullpath[128];
|
||||
snprintf(fullpath, sizeof(fullpath), "/spiffs/%s", filename[0] == '/' ? filename + 1 : filename);
|
||||
FILE *f = fopen(fullpath, "r");
|
||||
if (!f)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open file: %s", fullpath);
|
||||
*out_count = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t capacity = 16;
|
||||
size_t count = 0;
|
||||
char **lines = (char **)malloc(capacity * sizeof(char *));
|
||||
char line[256];
|
||||
while (fgets(line, sizeof(line), f))
|
||||
{
|
||||
// Zeilenumbruch entfernen
|
||||
char *pos = strchr(line, '\n');
|
||||
if (pos)
|
||||
*pos = '\0';
|
||||
// Trim vorne
|
||||
char *trimmed = line;
|
||||
while (*trimmed == ' ' || *trimmed == '\t')
|
||||
trimmed++;
|
||||
// Leere oder Kommentarzeile überspringen
|
||||
if (*trimmed == '\0' || *trimmed == '#')
|
||||
continue;
|
||||
// Trim hinten
|
||||
size_t len = strlen(trimmed);
|
||||
while (len > 0 && (trimmed[len - 1] == ' ' || trimmed[len - 1] == '\t'))
|
||||
trimmed[--len] = '\0';
|
||||
// Kopieren
|
||||
if (count >= capacity)
|
||||
{
|
||||
capacity *= 2;
|
||||
lines = (char **)realloc(lines, capacity * sizeof(char *));
|
||||
}
|
||||
lines[count++] = strdup(trimmed);
|
||||
}
|
||||
fclose(f);
|
||||
*out_count = (int)count;
|
||||
return lines;
|
||||
}
|
||||
|
||||
void free_lines(char **lines, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
free(lines[i]);
|
||||
free(lines);
|
||||
}
|
||||
|
||||
@@ -130,8 +130,10 @@ static void init_ui(void)
|
||||
|
||||
static void on_message_received(const message_t *msg)
|
||||
{
|
||||
if (msg && msg->type == MESSAGE_TYPE_SETTINGS && msg->data.settings.type == SETTINGS_TYPE_BOOL &&
|
||||
std::strcmp(msg->data.settings.key, "light_active") == 0)
|
||||
if (msg && msg->type == MESSAGE_TYPE_SETTINGS &&
|
||||
(std::strcmp(msg->data.settings.key, "light_active") == 0 ||
|
||||
std::strcmp(msg->data.settings.key, "light_variant") == 0 ||
|
||||
std::strcmp(msg->data.settings.key, "light_mode") == 0))
|
||||
{
|
||||
start_simulation();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user