new release
This commit is contained in:
@@ -1,12 +1,169 @@
|
||||
#include "meters_settings_api.h"
|
||||
#include "meter_manager.h" // Atualizado para usar o novo manager
|
||||
#include "meter_manager.h" // Atualizado para usar o novo manager
|
||||
#include "meter_events.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "cJSON.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_timer.h"
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG = "meters_settings_api";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
meter_event_data_t last_grid;
|
||||
meter_event_data_t last_evse;
|
||||
bool has_grid;
|
||||
bool has_evse;
|
||||
int64_t ts_grid_us;
|
||||
int64_t ts_evse_us;
|
||||
SemaphoreHandle_t mtx;
|
||||
} meters_cache_t;
|
||||
|
||||
static meters_cache_t g_cache = {0};
|
||||
|
||||
static void cache_init_once(void)
|
||||
{
|
||||
if (!g_cache.mtx)
|
||||
{
|
||||
g_cache.mtx = xSemaphoreCreateMutex();
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_event_locked(const meter_event_data_t *src)
|
||||
{
|
||||
if (!src)
|
||||
return;
|
||||
if (strcmp(src->source ? src->source : "", "EVSE") == 0)
|
||||
{
|
||||
g_cache.last_evse = *src;
|
||||
g_cache.has_evse = true;
|
||||
g_cache.ts_evse_us = esp_timer_get_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default trate como GRID
|
||||
g_cache.last_grid = *src;
|
||||
g_cache.has_grid = true;
|
||||
g_cache.ts_grid_us = esp_timer_get_time();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Event handler (atualiza cache) ----------
|
||||
static void meters_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
if (base != METER_EVENT || id != METER_EVENT_DATA_READY || data == NULL)
|
||||
return;
|
||||
|
||||
cache_init_once();
|
||||
if (xSemaphoreTake(g_cache.mtx, pdMS_TO_TICKS(10)) == pdTRUE)
|
||||
{
|
||||
copy_event_locked((const meter_event_data_t *)data);
|
||||
xSemaphoreGive(g_cache.mtx);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Helpers JSON ----------
|
||||
static cJSON *meter_event_to_json(const meter_event_data_t *m, int64_t ts_us)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(root, "source", m->source ? m->source : "GRID");
|
||||
cJSON_AddNumberToObject(root, "frequency", m->frequency);
|
||||
cJSON_AddNumberToObject(root, "powerFactor", m->power_factor);
|
||||
cJSON_AddNumberToObject(root, "totalEnergy", m->total_energy);
|
||||
|
||||
// timestamp relativo (segundos desde boot) e em micros
|
||||
cJSON_AddNumberToObject(root, "timestampUs", (double)ts_us);
|
||||
|
||||
// arrays
|
||||
cJSON *vr = cJSON_CreateArray();
|
||||
for (int i = 0; i < 3; i++)
|
||||
cJSON_AddItemToArray(vr, cJSON_CreateNumber(m->vrms[i]));
|
||||
cJSON *ir = cJSON_CreateArray();
|
||||
for (int i = 0; i < 3; i++)
|
||||
cJSON_AddItemToArray(ir, cJSON_CreateNumber(m->irms[i]));
|
||||
cJSON *pw = cJSON_CreateArray();
|
||||
for (int i = 0; i < 3; i++)
|
||||
cJSON_AddItemToArray(pw, cJSON_CreateNumber(m->watt[i]));
|
||||
cJSON_AddItemToObject(root, "vrms", vr);
|
||||
cJSON_AddItemToObject(root, "irms", ir);
|
||||
cJSON_AddItemToObject(root, "watt", pw);
|
||||
return root;
|
||||
}
|
||||
|
||||
// ---------- HTTP GET /api/v1/meters/live ----------
|
||||
static esp_err_t meters_live_get_handler(httpd_req_t *req)
|
||||
{
|
||||
cache_init_once();
|
||||
|
||||
char query[64] = {0};
|
||||
char source[16] = {0};
|
||||
bool want_grid = true, want_evse = true;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, query, sizeof(query)) == ESP_OK)
|
||||
{
|
||||
if (httpd_query_key_value(query, "source", source, sizeof(source)) == ESP_OK)
|
||||
{
|
||||
if (strcasecmp(source, "GRID") == 0)
|
||||
{
|
||||
want_grid = true;
|
||||
want_evse = false;
|
||||
}
|
||||
else if (strcasecmp(source, "EVSE") == 0)
|
||||
{
|
||||
want_grid = false;
|
||||
want_evse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cJSON *out = cJSON_CreateObject();
|
||||
cJSON *arr = cJSON_CreateArray();
|
||||
|
||||
if (xSemaphoreTake(g_cache.mtx, pdMS_TO_TICKS(50)) == pdTRUE)
|
||||
{
|
||||
if (want_grid && g_cache.has_grid)
|
||||
{
|
||||
cJSON_AddItemToArray(arr, meter_event_to_json(&g_cache.last_grid, g_cache.ts_grid_us));
|
||||
}
|
||||
if (want_evse && g_cache.has_evse)
|
||||
{
|
||||
cJSON_AddItemToArray(arr, meter_event_to_json(&g_cache.last_evse, g_cache.ts_evse_us));
|
||||
}
|
||||
xSemaphoreGive(g_cache.mtx);
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(out, "meters", arr);
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
char *s = cJSON_PrintUnformatted(out);
|
||||
httpd_resp_sendstr(req, s ? s : "{\"meters\":[]}");
|
||||
if (s)
|
||||
free(s);
|
||||
cJSON_Delete(out);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// ---------- Registro ----------
|
||||
void register_meters_data_handlers(httpd_handle_t server, void *ctx)
|
||||
{
|
||||
// registra event handler para receber amostras
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(METER_EVENT, METER_EVENT_DATA_READY, meters_event_handler, NULL));
|
||||
|
||||
// endpoint GET
|
||||
httpd_uri_t live = {
|
||||
.uri = "/api/v1/meters/live",
|
||||
.method = HTTP_GET,
|
||||
.handler = meters_live_get_handler,
|
||||
.user_ctx = ctx};
|
||||
httpd_register_uri_handler(server, &live);
|
||||
|
||||
ESP_LOGI(TAG, "REST /api/v1/meters/live registrado");
|
||||
}
|
||||
|
||||
// Função para recuperar as configurações dos contadores
|
||||
static esp_err_t meters_config_get_handler(httpd_req_t *req) {
|
||||
static esp_err_t meters_config_get_handler(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGI(TAG, "Received GET request for /api/v1/config/meters");
|
||||
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
@@ -38,24 +195,27 @@ static esp_err_t meters_config_get_handler(httpd_req_t *req) {
|
||||
}
|
||||
|
||||
// Função para atualizar as configurações dos contadores
|
||||
static esp_err_t meters_config_post_handler(httpd_req_t *req) {
|
||||
static esp_err_t meters_config_post_handler(httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGI(TAG, "Received POST request for /api/v1/config/meters");
|
||||
|
||||
char buf[512];
|
||||
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len <= 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Received empty body in POST request");
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
buf[len] = '\0'; // Garantir que a string está terminada
|
||||
buf[len] = '\0'; // Garantir que a string está terminada
|
||||
|
||||
ESP_LOGI(TAG, "Received POST data: %s", buf);
|
||||
|
||||
cJSON *json = cJSON_Parse(buf);
|
||||
if (!json) {
|
||||
if (!json)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to parse JSON data");
|
||||
// Resposta detalhada de erro
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON format");
|
||||
@@ -64,15 +224,17 @@ static esp_err_t meters_config_post_handler(httpd_req_t *req) {
|
||||
|
||||
// Atualizando os contadores
|
||||
cJSON *gridmeter = cJSON_GetObjectItem(json, "gridmeter");
|
||||
if (gridmeter) {
|
||||
meter_type_t gridType = string_to_meter_type(gridmeter->valuestring); // Usando a função string_to_meter_type
|
||||
if (gridmeter)
|
||||
{
|
||||
meter_type_t gridType = string_to_meter_type(gridmeter->valuestring); // Usando a função string_to_meter_type
|
||||
ESP_LOGI(TAG, "Updating grid meter type to: %s", gridmeter->valuestring);
|
||||
meter_manager_grid_set_model(gridType);
|
||||
}
|
||||
|
||||
cJSON *evsemeter = cJSON_GetObjectItem(json, "evsemeter");
|
||||
if (evsemeter) {
|
||||
meter_type_t evseType = string_to_meter_type(evsemeter->valuestring); // Usando a função string_to_meter_type
|
||||
if (evsemeter)
|
||||
{
|
||||
meter_type_t evseType = string_to_meter_type(evsemeter->valuestring); // Usando a função string_to_meter_type
|
||||
ESP_LOGI(TAG, "Updating EVSE meter type to: %s", evsemeter->valuestring);
|
||||
meter_manager_evse_set_model(evseType);
|
||||
}
|
||||
@@ -86,7 +248,8 @@ static esp_err_t meters_config_post_handler(httpd_req_t *req) {
|
||||
}
|
||||
|
||||
// Registrando os manipuladores de URI para os contadores
|
||||
void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
|
||||
void register_meters_settings_handlers(httpd_handle_t server, void *ctx)
|
||||
{
|
||||
ESP_LOGD(TAG, "Registering URI handlers for meters settings");
|
||||
|
||||
// URI para o método GET
|
||||
@@ -94,8 +257,7 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
|
||||
.uri = "/api/v1/config/meters",
|
||||
.method = HTTP_GET,
|
||||
.handler = meters_config_get_handler,
|
||||
.user_ctx = ctx
|
||||
};
|
||||
.user_ctx = ctx};
|
||||
ESP_LOGD(TAG, "Registering GET handler for /api/v1/config/meters");
|
||||
httpd_register_uri_handler(server, &meters_get_uri);
|
||||
|
||||
@@ -104,8 +266,7 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
|
||||
.uri = "/api/v1/config/meters",
|
||||
.method = HTTP_POST,
|
||||
.handler = meters_config_post_handler,
|
||||
.user_ctx = ctx
|
||||
};
|
||||
.user_ctx = ctx};
|
||||
ESP_LOGD(TAG, "Registering POST handler for /api/v1/config/meters");
|
||||
httpd_register_uri_handler(server, &meters_post_uri);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user