new module
This commit is contained in:
@@ -8,6 +8,7 @@ set(srcs
|
||||
"src/loadbalancing_settings_api.c"
|
||||
"src/evse_link_config_api.c"
|
||||
"src/dashboard_api.c"
|
||||
"src/scheduler_settings_api.c"
|
||||
"src/static_file_api.c"
|
||||
)
|
||||
|
||||
@@ -15,7 +16,7 @@ idf_component_register(
|
||||
SRCS ${srcs}
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "src"
|
||||
PRIV_REQUIRES nvs_flash esp_http_server esp_netif vfs spiffs json evse meter_manager protocols loadbalancer evse_link
|
||||
PRIV_REQUIRES nvs_flash esp_http_server esp_netif vfs spiffs json evse meter_manager protocols loadbalancer evse_link scheduler
|
||||
)
|
||||
|
||||
# SPIFFS image (opcional)
|
||||
|
||||
23
components/rest_api/include/scheduler_settings_api.h
Executable file
23
components/rest_api/include/scheduler_settings_api.h
Executable file
@@ -0,0 +1,23 @@
|
||||
// =========================
|
||||
// scheduler_settings_api.h
|
||||
// =========================
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_http_server.h"
|
||||
|
||||
/**
|
||||
* @brief Registra os handlers de configuração do scheduler
|
||||
*
|
||||
* Endpoints:
|
||||
* GET /api/v1/config/scheduler
|
||||
* POST /api/v1/config/scheduler
|
||||
*/
|
||||
void register_scheduler_settings_handlers(httpd_handle_t server, void *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "ocpp_api.h"
|
||||
#include "auth_api.h"
|
||||
#include "dashboard_api.h"
|
||||
#include "scheduler_settings_api.h"
|
||||
#include "static_file_api.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
@@ -49,8 +50,8 @@ esp_err_t rest_server_init(const char *base_path)
|
||||
register_meters_settings_handlers(server, ctx); // Apenas chamando a função sem comparação
|
||||
register_loadbalancing_settings_handlers(server, ctx); // Apenas chamando a função sem comparação
|
||||
register_link_config_handlers(server, ctx);
|
||||
|
||||
register_meters_data_handlers(server, ctx);
|
||||
register_scheduler_settings_handlers(server, ctx);
|
||||
|
||||
register_static_file_handlers(server, ctx); // Apenas chamando a função sem comparação
|
||||
|
||||
|
||||
224
components/rest_api/src/scheduler_settings_api.c
Executable file
224
components/rest_api/src/scheduler_settings_api.c
Executable file
@@ -0,0 +1,224 @@
|
||||
#include "scheduler_settings_api.h"
|
||||
#include "scheduler.h"
|
||||
#include "scheduler_types.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h> // sscanf, snprintf
|
||||
|
||||
static const char *TAG = "scheduler_api";
|
||||
|
||||
/* =========================
|
||||
* Helpers HH:MM <-> minutos
|
||||
* ========================= */
|
||||
|
||||
static bool parse_hhmm(const char *s, uint16_t *out_min)
|
||||
{
|
||||
if (!s || !out_min)
|
||||
return false;
|
||||
|
||||
// formato esperado: "HH:MM"
|
||||
int h = 0, m = 0;
|
||||
if (sscanf(s, "%d:%d", &h, &m) != 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (h < 0 || h > 23 || m < 0 || m > 59)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*out_min = (uint16_t)(h * 60 + m);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void format_hhmm(uint16_t minutes, char *buf, size_t buf_sz)
|
||||
{
|
||||
if (!buf || buf_sz < 6)
|
||||
return;
|
||||
minutes %= (24 * 60);
|
||||
int h = minutes / 60;
|
||||
int m = minutes % 60;
|
||||
snprintf(buf, buf_sz, "%02d:%02d", h, m);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* GET /api/v1/config/scheduler
|
||||
* ========================= */
|
||||
static esp_err_t scheduler_config_get_handler(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGI(TAG, "GET /api/v1/config/scheduler");
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
|
||||
sched_config_t cfg = scheduler_get_config();
|
||||
bool allowed_now = scheduler_is_allowed_now();
|
||||
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
if (!root)
|
||||
{
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "cJSON alloc failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
cJSON_AddBoolToObject(root, "enabled", cfg.enabled);
|
||||
cJSON_AddStringToObject(root, "mode", sched_mode_to_str(cfg.mode));
|
||||
|
||||
char buf[8];
|
||||
format_hhmm(cfg.start_min, buf, sizeof(buf));
|
||||
cJSON_AddStringToObject(root, "startTime", buf);
|
||||
format_hhmm(cfg.end_min, buf, sizeof(buf));
|
||||
cJSON_AddStringToObject(root, "endTime", buf);
|
||||
|
||||
cJSON_AddBoolToObject(root, "allowedNow", allowed_now);
|
||||
|
||||
char *json_str = cJSON_PrintUnformatted(root);
|
||||
if (!json_str)
|
||||
{
|
||||
cJSON_Delete(root);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "cJSON print failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
httpd_resp_sendstr(req, json_str);
|
||||
|
||||
free(json_str);
|
||||
cJSON_Delete(root);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* POST /api/v1/config/scheduler
|
||||
* ========================= */
|
||||
static esp_err_t scheduler_config_post_handler(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGI(TAG, "POST /api/v1/config/scheduler");
|
||||
|
||||
// NOTA: para payloads pequenos 512 bytes chega; se quiseres robustez total,
|
||||
// usa req->content_len e faz um loop com httpd_req_recv.
|
||||
char buf[512];
|
||||
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
||||
if (len <= 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Empty body / recv error");
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
ESP_LOGI(TAG, "Body: %s", buf);
|
||||
|
||||
cJSON *json = cJSON_Parse(buf);
|
||||
if (!json)
|
||||
{
|
||||
ESP_LOGE(TAG, "Invalid JSON");
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Começa a partir da config atual
|
||||
sched_config_t cfg = scheduler_get_config();
|
||||
|
||||
// enabled
|
||||
cJSON *j_enabled = cJSON_GetObjectItem(json, "enabled");
|
||||
if (cJSON_IsBool(j_enabled))
|
||||
{
|
||||
cfg.enabled = cJSON_IsTrue(j_enabled);
|
||||
ESP_LOGI(TAG, " enabled = %d", cfg.enabled);
|
||||
}
|
||||
|
||||
// mode
|
||||
cJSON *j_mode = cJSON_GetObjectItem(json, "mode");
|
||||
if (cJSON_IsString(j_mode) && j_mode->valuestring)
|
||||
{
|
||||
sched_mode_t m;
|
||||
if (!sched_mode_from_str(j_mode->valuestring, &m))
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid mode: %s", j_mode->valuestring);
|
||||
cJSON_Delete(json);
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
|
||||
"Invalid mode (use: disabled|simple|weekly)");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
cfg.mode = m;
|
||||
ESP_LOGI(TAG, " mode = %s", sched_mode_to_str(cfg.mode));
|
||||
}
|
||||
|
||||
// startTime (string "HH:MM")
|
||||
cJSON *j_start = cJSON_GetObjectItem(json, "startTime");
|
||||
if (cJSON_IsString(j_start) && j_start->valuestring)
|
||||
{
|
||||
uint16_t minutes = 0;
|
||||
if (!parse_hhmm(j_start->valuestring, &minutes))
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid startTime: %s", j_start->valuestring);
|
||||
cJSON_Delete(json);
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
|
||||
"Invalid startTime (use HH:MM)");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
cfg.start_min = minutes;
|
||||
ESP_LOGI(TAG, " start_min = %u", (unsigned)cfg.start_min);
|
||||
}
|
||||
|
||||
// endTime (string "HH:MM")
|
||||
cJSON *j_end = cJSON_GetObjectItem(json, "endTime");
|
||||
if (cJSON_IsString(j_end) && j_end->valuestring)
|
||||
{
|
||||
uint16_t minutes = 0;
|
||||
if (!parse_hhmm(j_end->valuestring, &minutes))
|
||||
{
|
||||
ESP_LOGW(TAG, "Invalid endTime: %s", j_end->valuestring);
|
||||
cJSON_Delete(json);
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
|
||||
"Invalid endTime (use HH:MM)");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
cfg.end_min = minutes;
|
||||
ESP_LOGI(TAG, " end_min = %u", (unsigned)cfg.end_min);
|
||||
}
|
||||
|
||||
// (Opcional) validações extra:
|
||||
// exemplo: impedir janela vazia quando ativo
|
||||
/*
|
||||
if (cfg.enabled && cfg.mode != SCHED_MODE_DISABLED &&
|
||||
cfg.start_min == cfg.end_min) {
|
||||
cJSON_Delete(json);
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
|
||||
"startTime and endTime cannot be equal");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
*/
|
||||
|
||||
// Aplica config no módulo scheduler (ele trata de NVS + eventos)
|
||||
scheduler_set_config(&cfg);
|
||||
|
||||
cJSON_Delete(json);
|
||||
|
||||
httpd_resp_sendstr(req, "Scheduler config atualizada com sucesso");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Registo dos handlers
|
||||
* ========================= */
|
||||
void register_scheduler_settings_handlers(httpd_handle_t server, void *ctx)
|
||||
{
|
||||
httpd_uri_t get_uri = {
|
||||
.uri = "/api/v1/config/scheduler",
|
||||
.method = HTTP_GET,
|
||||
.handler = scheduler_config_get_handler,
|
||||
.user_ctx = ctx};
|
||||
httpd_register_uri_handler(server, &get_uri);
|
||||
|
||||
httpd_uri_t post_uri = {
|
||||
.uri = "/api/v1/config/scheduler",
|
||||
.method = HTTP_POST,
|
||||
.handler = scheduler_config_post_handler,
|
||||
.user_ctx = ctx};
|
||||
httpd_register_uri_handler(server, &post_uri);
|
||||
|
||||
ESP_LOGI(TAG, "Scheduler REST handlers registered");
|
||||
}
|
||||
Reference in New Issue
Block a user