897 lines
27 KiB
C
Executable File
897 lines
27 KiB
C
Executable File
|
|
|
|
// === Início de: components/auth/include/auth.h ===
|
|
#ifndef AUTH_H
|
|
#define AUTH_H
|
|
|
|
#include <stdbool.h>
|
|
#include <freertos/FreeRTOS.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/// Tamanho máximo de uma tag RFID (incluindo '\0')
|
|
#define AUTH_TAG_MAX_LEN 20
|
|
|
|
/// Estrutura de evento emitida após leitura de uma tag
|
|
typedef struct {
|
|
char tag[AUTH_TAG_MAX_LEN]; ///< Tag lida
|
|
bool authorized; ///< true se a tag for reconhecida como válida
|
|
} auth_event_t;
|
|
|
|
/**
|
|
* @brief Inicializa o sistema de autenticação.
|
|
*
|
|
* - Carrega a configuração (enabled) da NVS
|
|
* - Inicia o leitor Wiegand
|
|
* - Emite evento AUTH_EVENT_INIT com estado atual
|
|
*/
|
|
void auth_init(void);
|
|
|
|
/**
|
|
* @brief Ativa ou desativa o uso de autenticação via RFID.
|
|
*
|
|
* Esta configuração é persistida em NVS. Se desativado, o sistema
|
|
* considerará todas as autorizações como aceitas.
|
|
*
|
|
* @param value true para ativar, false para desativar
|
|
*/
|
|
void auth_set_enabled(bool value);
|
|
|
|
/**
|
|
* @brief Verifica se o sistema de autenticação está habilitado.
|
|
*/
|
|
bool auth_is_enabled(void);
|
|
|
|
/**
|
|
* @brief Adiciona uma nova tag RFID à lista de autorizadas.
|
|
*
|
|
* @param tag String da tag (máx AUTH_TAG_MAX_LEN-1)
|
|
* @return true se a tag foi adicionada, false se já existia ou inválida
|
|
*/
|
|
bool auth_add_tag(const char *tag);
|
|
|
|
/**
|
|
* @brief Remove uma tag previamente cadastrada.
|
|
*
|
|
* @param tag String da tag
|
|
* @return true se foi removida, false se não encontrada
|
|
*/
|
|
bool auth_remove_tag(const char *tag);
|
|
|
|
/**
|
|
* @brief Verifica se uma tag já está registrada como válida.
|
|
*/
|
|
bool auth_tag_exists(const char *tag);
|
|
|
|
/**
|
|
* @brief Lista todas as tags válidas atualmente registradas (via logs).
|
|
*/
|
|
void auth_list_tags(void);
|
|
|
|
/**
|
|
* @brief Processa uma tag RFID lida (chamada normalmente pelo leitor).
|
|
*
|
|
* - Verifica validade
|
|
* - Emite evento AUTH_EVENT_TAG_PROCESSED
|
|
* - Inicia timer de expiração se autorizada
|
|
*/
|
|
void auth_process_tag(const char *tag);
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // AUTH_H
|
|
|
|
// === Fim de: components/auth/include/auth.h ===
|
|
|
|
|
|
// === Início de: components/auth/include/auth_events.h ===
|
|
#pragma once
|
|
#include "esp_event.h"
|
|
|
|
#define AUTH_EVENT_TAG_MAX_LEN 32
|
|
|
|
ESP_EVENT_DECLARE_BASE(AUTH_EVENTS);
|
|
|
|
typedef enum {
|
|
AUTH_EVENT_TAG_PROCESSED,
|
|
AUTH_EVENT_ENABLED_CHANGED,
|
|
AUTH_EVENT_INIT,
|
|
} auth_event_id_t;
|
|
|
|
typedef struct {
|
|
char tag[AUTH_EVENT_TAG_MAX_LEN];
|
|
bool authorized;
|
|
} auth_tag_event_data_t;
|
|
|
|
typedef struct {
|
|
bool enabled;
|
|
} auth_enabled_event_data_t;
|
|
|
|
// === Fim de: components/auth/include/auth_events.h ===
|
|
|
|
|
|
// === Início de: components/auth/include/wiegand.h ===
|
|
/*
|
|
* Copyright (c) 2021 Ruslan V. Uss <unclerus@gmail.com>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the names of itscontributors
|
|
* may be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* @file wiegand.h
|
|
* @defgroup wiegand wiegand
|
|
* @{
|
|
*
|
|
* ESP-IDF Wiegand protocol receiver
|
|
*
|
|
* Copyright (c) 2021 Ruslan V. Uss <unclerus@gmail.com>
|
|
*
|
|
* BSD Licensed as described in the file LICENSE
|
|
*/
|
|
#ifndef __WIEGAND_H__
|
|
#define __WIEGAND_H__
|
|
|
|
#include <driver/gpio.h>
|
|
#include <esp_err.h>
|
|
#include <esp_timer.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
typedef struct wiegand_reader wiegand_reader_t;
|
|
|
|
typedef void (*wiegand_callback_t)(wiegand_reader_t *reader);
|
|
|
|
/**
|
|
* Bit and byte order of data
|
|
*/
|
|
typedef enum {
|
|
WIEGAND_MSB_FIRST = 0,
|
|
WIEGAND_LSB_FIRST
|
|
} wiegand_order_t;
|
|
|
|
/**
|
|
* Wiegand reader descriptor
|
|
*/
|
|
struct wiegand_reader
|
|
{
|
|
gpio_num_t gpio_d0, gpio_d1;
|
|
wiegand_callback_t callback;
|
|
wiegand_order_t bit_order;
|
|
wiegand_order_t byte_order;
|
|
|
|
uint8_t *buf;
|
|
size_t size;
|
|
size_t bits;
|
|
esp_timer_handle_t timer;
|
|
bool start_parity;
|
|
bool enabled;
|
|
};
|
|
|
|
/**
|
|
* @brief Create and initialize reader instance.
|
|
*
|
|
* @param reader Reader descriptor
|
|
* @param gpio_d0 GPIO pin for D0
|
|
* @param gpio_d1 GPIO pin for D0
|
|
* @param internal_pullups Enable internal pull-up resistors for D0 and D1 GPIO
|
|
* @param buf_size Reader buffer size in bytes, must be large enough to
|
|
* contain entire Wiegand key
|
|
* @param callback Callback function for processing received codes
|
|
* @param bit_order Bit order of data
|
|
* @param byte_order Byte order of data
|
|
* @return `ESP_OK` on success
|
|
*/
|
|
esp_err_t wiegand_reader_init(wiegand_reader_t *reader, gpio_num_t gpio_d0, gpio_num_t gpio_d1,
|
|
bool internal_pullups, size_t buf_size, wiegand_callback_t callback, wiegand_order_t bit_order,
|
|
wiegand_order_t byte_order);
|
|
|
|
/**
|
|
* @brief Disable reader
|
|
*
|
|
* While reader is disabled, it will not receive new data
|
|
*
|
|
* @param reader Reader descriptor
|
|
* @return `ESP_OK` on success
|
|
*/
|
|
esp_err_t wiegand_reader_disable(wiegand_reader_t *reader);
|
|
|
|
/**
|
|
* @brief Enable reader
|
|
*
|
|
* @param reader Reader descriptor
|
|
* @return `ESP_OK` on success
|
|
*/
|
|
esp_err_t wiegand_reader_enable(wiegand_reader_t *reader);
|
|
|
|
/**
|
|
* @brief Delete reader instance.
|
|
*
|
|
* @param reader Reader descriptor
|
|
* @return `ESP_OK` on success
|
|
*/
|
|
esp_err_t wiegand_reader_done(wiegand_reader_t *reader);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
/**@}*/
|
|
|
|
#endif /* __WIEGAND_H__ */
|
|
|
|
// === Fim de: components/auth/include/wiegand.h ===
|
|
|
|
|
|
// === Início de: components/auth/include/wiegand_reader.h ===
|
|
#ifndef WIEGAND_READER_H
|
|
#define WIEGAND_READER_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
void initWiegand(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif // WIEGAND_READER_H
|
|
|
|
// === Fim de: components/auth/include/wiegand_reader.h ===
|
|
|
|
|
|
// === Início de: components/rest_api/src/ocpp_api.c ===
|
|
// =========================
|
|
// ocpp_api.c
|
|
// =========================
|
|
#include "ocpp_api.h"
|
|
#include "esp_log.h"
|
|
#include "cJSON.h"
|
|
|
|
static const char *TAG = "ocpp_api";
|
|
|
|
static struct {
|
|
char url[256];
|
|
char chargeBoxId[128];
|
|
char certificate[256];
|
|
char privateKey[256];
|
|
} ocpp_config = {"", "", "", ""};
|
|
|
|
static esp_err_t ocpp_get_status_handler(httpd_req_t *req) {
|
|
httpd_resp_set_type(req, "application/json");
|
|
cJSON *status = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(status, "status", "connected");
|
|
char *str = cJSON_Print(status);
|
|
httpd_resp_sendstr(req, str);
|
|
free(str);
|
|
cJSON_Delete(status);
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t ocpp_get_config_handler(httpd_req_t *req) {
|
|
httpd_resp_set_type(req, "application/json");
|
|
cJSON *json = cJSON_CreateObject();
|
|
cJSON_AddStringToObject(json, "url", ocpp_config.url);
|
|
cJSON_AddStringToObject(json, "chargeBoxId", ocpp_config.chargeBoxId);
|
|
cJSON_AddStringToObject(json, "certificate", ocpp_config.certificate);
|
|
cJSON_AddStringToObject(json, "privateKey", ocpp_config.privateKey);
|
|
char *str = cJSON_Print(json);
|
|
httpd_resp_sendstr(req, str);
|
|
free(str);
|
|
cJSON_Delete(json);
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t ocpp_post_config_handler(httpd_req_t *req) {
|
|
char buf[512];
|
|
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
|
if (len <= 0) {
|
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body");
|
|
return ESP_FAIL;
|
|
}
|
|
buf[len] = '\0';
|
|
cJSON *json = cJSON_Parse(buf);
|
|
if (!json) {
|
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
|
|
return ESP_FAIL;
|
|
}
|
|
cJSON *url = cJSON_GetObjectItem(json, "url");
|
|
if (url) strlcpy(ocpp_config.url, url->valuestring, sizeof(ocpp_config.url));
|
|
cJSON *id = cJSON_GetObjectItem(json, "chargeBoxId");
|
|
if (id) strlcpy(ocpp_config.chargeBoxId, id->valuestring, sizeof(ocpp_config.chargeBoxId));
|
|
cJSON *cert = cJSON_GetObjectItem(json, "certificate");
|
|
if (cert) strlcpy(ocpp_config.certificate, cert->valuestring, sizeof(ocpp_config.certificate));
|
|
cJSON *key = cJSON_GetObjectItem(json, "privateKey");
|
|
if (key) strlcpy(ocpp_config.privateKey, key->valuestring, sizeof(ocpp_config.privateKey));
|
|
cJSON_Delete(json);
|
|
httpd_resp_sendstr(req, "OCPP config atualizada com sucesso");
|
|
return ESP_OK;
|
|
}
|
|
|
|
void register_ocpp_handlers(httpd_handle_t server, void *ctx) {
|
|
httpd_uri_t status_uri = {
|
|
.uri = "/api/v1/ocpp",
|
|
.method = HTTP_GET,
|
|
.handler = ocpp_get_status_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &status_uri);
|
|
|
|
httpd_uri_t get_uri = {
|
|
.uri = "/api/v1/config/ocpp",
|
|
.method = HTTP_GET,
|
|
.handler = ocpp_get_config_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &get_uri);
|
|
|
|
httpd_uri_t post_uri = {
|
|
.uri = "/api/v1/config/ocpp",
|
|
.method = HTTP_POST,
|
|
.handler = ocpp_post_config_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &post_uri);
|
|
}
|
|
|
|
// === Fim de: components/rest_api/src/ocpp_api.c ===
|
|
|
|
|
|
// === Início de: components/rest_api/src/static_file_api.c ===
|
|
#include "static_file_api.h"
|
|
#include "esp_log.h"
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include "esp_vfs.h"
|
|
|
|
static const char *TAG = "static_file_api";
|
|
|
|
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
|
|
#define SCRATCH_BUFSIZE (10240)
|
|
|
|
typedef struct rest_server_context {
|
|
char base_path[ESP_VFS_PATH_MAX + 1];
|
|
char scratch[SCRATCH_BUFSIZE];
|
|
} rest_server_context_t;
|
|
|
|
#define CHECK_FILE_EXTENSION(filename, ext) \
|
|
(strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
|
|
|
|
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath) {
|
|
const char *type = "text/plain";
|
|
if (CHECK_FILE_EXTENSION(filepath, ".html")) type = "text/html";
|
|
else if (CHECK_FILE_EXTENSION(filepath, ".js")) type = "application/javascript";
|
|
else if (CHECK_FILE_EXTENSION(filepath, ".css")) type = "text/css";
|
|
else if (CHECK_FILE_EXTENSION(filepath, ".png")) type = "image/png";
|
|
else if (CHECK_FILE_EXTENSION(filepath, ".ico")) type = "image/x-icon";
|
|
else if (CHECK_FILE_EXTENSION(filepath, ".svg")) type = "image/svg+xml";
|
|
return httpd_resp_set_type(req, type);
|
|
}
|
|
|
|
static esp_err_t static_get_handler(httpd_req_t *req) {
|
|
char filepath[FILE_PATH_MAX];
|
|
rest_server_context_t *ctx = (rest_server_context_t *) req->user_ctx;
|
|
|
|
strlcpy(filepath, ctx->base_path, sizeof(filepath));
|
|
if (req->uri[strlen(req->uri) - 1] == '/') {
|
|
strlcat(filepath, "/index.html", sizeof(filepath));
|
|
} else {
|
|
strlcat(filepath, req->uri, sizeof(filepath));
|
|
}
|
|
|
|
int fd = open(filepath, O_RDONLY, 0);
|
|
if (fd == -1) {
|
|
// fallback para /index.html (SPA)
|
|
ESP_LOGW(TAG, "Arquivo não encontrado: %s. Tentando index.html", filepath);
|
|
strlcpy(filepath, ctx->base_path, sizeof(filepath));
|
|
strlcat(filepath, "/index.html", sizeof(filepath));
|
|
fd = open(filepath, O_RDONLY, 0);
|
|
if (fd == -1) {
|
|
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Arquivo não encontrado");
|
|
return ESP_FAIL;
|
|
}
|
|
}
|
|
|
|
set_content_type_from_file(req, filepath);
|
|
|
|
char *chunk = ctx->scratch;
|
|
ssize_t read_bytes;
|
|
do {
|
|
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
|
|
if (read_bytes == -1) {
|
|
ESP_LOGE(TAG, "Erro lendo arquivo: %s", filepath);
|
|
close(fd);
|
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao ler arquivo");
|
|
return ESP_FAIL;
|
|
} else if (read_bytes > 0) {
|
|
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
|
|
close(fd);
|
|
httpd_resp_sendstr_chunk(req, NULL);
|
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao enviar arquivo");
|
|
return ESP_FAIL;
|
|
}
|
|
}
|
|
} while (read_bytes > 0);
|
|
|
|
close(fd);
|
|
httpd_resp_send_chunk(req, NULL, 0);
|
|
return ESP_OK;
|
|
}
|
|
|
|
void register_static_file_handlers(httpd_handle_t server, void *ctx) {
|
|
httpd_uri_t uri = {
|
|
.uri = "/*",
|
|
.method = HTTP_GET,
|
|
.handler = static_get_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &uri);
|
|
}
|
|
|
|
// === Fim de: components/rest_api/src/static_file_api.c ===
|
|
|
|
|
|
// === Início de: components/rest_api/src/meters_settings_api.c ===
|
|
#include "meters_settings_api.h"
|
|
#include "meter_manager.h" // Atualizado para usar o novo manager
|
|
#include "esp_log.h"
|
|
#include "cJSON.h"
|
|
|
|
static const char *TAG = "meters_settings_api";
|
|
|
|
// Função para recuperar as configurações dos contadores
|
|
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");
|
|
|
|
cJSON *config = cJSON_CreateObject();
|
|
|
|
// Recuperando as configurações dos contadores
|
|
meter_type_t gridmeterType = meter_manager_grid_get_model();
|
|
meter_type_t evsemeterType = meter_manager_evse_get_model();
|
|
|
|
ESP_LOGI(TAG, "Grid meter type: %s", meter_type_to_str(gridmeterType));
|
|
ESP_LOGI(TAG, "EVSE meter type: %s", meter_type_to_str(evsemeterType));
|
|
|
|
// Adicionando os tipos de contadores ao objeto JSON
|
|
cJSON_AddStringToObject(config, "gridmeter", meter_type_to_str(gridmeterType));
|
|
cJSON_AddStringToObject(config, "evsemeter", meter_type_to_str(evsemeterType));
|
|
|
|
// Convertendo o objeto JSON para uma string
|
|
const char *json_str = cJSON_Print(config);
|
|
ESP_LOGI(TAG, "Returning meters config: %s", json_str);
|
|
|
|
httpd_resp_sendstr(req, json_str);
|
|
|
|
// Liberação da memória
|
|
free((void *)json_str);
|
|
cJSON_Delete(config);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
// Função para atualizar as configurações dos contadores
|
|
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) {
|
|
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
|
|
|
|
ESP_LOGI(TAG, "Received POST data: %s", buf);
|
|
|
|
cJSON *json = cJSON_Parse(buf);
|
|
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");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
// 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
|
|
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
|
|
ESP_LOGI(TAG, "Updating EVSE meter type to: %s", evsemeter->valuestring);
|
|
meter_manager_evse_set_model(evseType);
|
|
}
|
|
|
|
cJSON_Delete(json);
|
|
httpd_resp_sendstr(req, "Meters updated successfully");
|
|
|
|
ESP_LOGI(TAG, "Meters configuration updated successfully");
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
// Registrando os manipuladores de URI para os contadores
|
|
void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
|
|
ESP_LOGI(TAG, "Registering URI handlers for meters settings");
|
|
|
|
// URI para o método GET
|
|
httpd_uri_t meters_get_uri = {
|
|
.uri = "/api/v1/config/meters",
|
|
.method = HTTP_GET,
|
|
.handler = meters_config_get_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
ESP_LOGI(TAG, "Registering GET handler for /api/v1/config/meters");
|
|
httpd_register_uri_handler(server, &meters_get_uri);
|
|
|
|
// URI para o método POST
|
|
httpd_uri_t meters_post_uri = {
|
|
.uri = "/api/v1/config/meters",
|
|
.method = HTTP_POST,
|
|
.handler = meters_config_post_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
ESP_LOGI(TAG, "Registering POST handler for /api/v1/config/meters");
|
|
httpd_register_uri_handler(server, &meters_post_uri);
|
|
}
|
|
|
|
// === Fim de: components/rest_api/src/meters_settings_api.c ===
|
|
|
|
|
|
// === Início de: components/rest_api/src/rest_main.c ===
|
|
#include "rest_main.h"
|
|
#include "evse_settings_api.h"
|
|
#include "meters_settings_api.h"
|
|
#include "loadbalancing_settings_api.h"
|
|
#include "network_api.h"
|
|
#include "ocpp_api.h"
|
|
#include "auth_api.h"
|
|
#include "dashboard_api.h"
|
|
#include "static_file_api.h"
|
|
#include "esp_log.h"
|
|
|
|
|
|
static const char *TAG = "rest_main";
|
|
|
|
esp_err_t rest_server_init(const char *base_path) {
|
|
ESP_LOGI(TAG, "Initializing REST API with base path: %s", base_path);
|
|
|
|
rest_server_context_t *ctx = calloc(1, sizeof(rest_server_context_t));
|
|
if (!ctx) {
|
|
ESP_LOGE(TAG, "Failed to allocate memory for REST context");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
strlcpy(ctx->base_path, base_path, sizeof(ctx->base_path));
|
|
|
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
|
config.uri_match_fn = httpd_uri_match_wildcard;
|
|
config.max_uri_handlers = 32;
|
|
|
|
httpd_handle_t server = NULL;
|
|
esp_err_t err = httpd_start(&server, &config);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to start HTTP server: %s", esp_err_to_name(err));
|
|
free(ctx);
|
|
return err;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "HTTP server started successfully");
|
|
|
|
// Register endpoint groups
|
|
register_evse_settings_handlers(server, ctx); // Apenas chamando a função sem comparação
|
|
register_network_handlers(server, ctx); // Apenas chamando a função sem comparação
|
|
register_ocpp_handlers(server, ctx); // Apenas chamando a função sem comparação
|
|
register_auth_handlers(server, ctx); // Apenas chamando a função sem comparação
|
|
register_dashboard_handlers(server, ctx); // Apenas chamando a função sem comparação
|
|
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_static_file_handlers(server, ctx); // Apenas chamando a função sem comparação
|
|
|
|
ESP_LOGI(TAG, "All REST API endpoint groups registered successfully");
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
// === Fim de: components/rest_api/src/rest_main.c ===
|
|
|
|
|
|
// === Início de: components/rest_api/src/network_api.c ===
|
|
// =========================
|
|
// network_api.c
|
|
// =========================
|
|
|
|
#include "network_api.h"
|
|
#include "esp_log.h"
|
|
#include "cJSON.h"
|
|
#include "wifi.h"
|
|
#include "mqtt.h"
|
|
|
|
static const char *TAG = "network_api";
|
|
|
|
typedef struct {
|
|
bool enabled;
|
|
char ssid[33];
|
|
char password[65];
|
|
} wifi_task_data_t;
|
|
|
|
|
|
static void wifi_apply_config_task(void *param) {
|
|
wifi_task_data_t *data = (wifi_task_data_t *)param;
|
|
ESP_LOGI("wifi_task", "Applying Wi-Fi config in background task");
|
|
wifi_set_config(data->enabled, data->ssid, data->password);
|
|
free(data);
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
static esp_err_t wifi_get_handler(httpd_req_t *req) {
|
|
ESP_LOGI(TAG, "Handling GET /api/v1/config/wifi");
|
|
|
|
httpd_resp_set_type(req, "application/json");
|
|
|
|
// Obter dados da NVS via wifi.c
|
|
bool enabled = wifi_get_enabled();
|
|
char ssid[33] = {0};
|
|
char password[65] = {0};
|
|
|
|
wifi_get_ssid(ssid);
|
|
wifi_get_password(password);
|
|
|
|
// Criar JSON
|
|
cJSON *json = cJSON_CreateObject();
|
|
cJSON_AddBoolToObject(json, "enabled", enabled);
|
|
cJSON_AddStringToObject(json, "ssid", ssid);
|
|
cJSON_AddStringToObject(json, "password", password);
|
|
|
|
// Enviar resposta
|
|
char *response = cJSON_Print(json);
|
|
httpd_resp_sendstr(req, response);
|
|
|
|
// Limpeza
|
|
free(response);
|
|
cJSON_Delete(json);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t wifi_post_handler(httpd_req_t *req) {
|
|
ESP_LOGI(TAG, "Handling POST /api/v1/config/wifi");
|
|
|
|
char buf[512];
|
|
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
|
if (len <= 0) return ESP_FAIL;
|
|
buf[len] = '\0';
|
|
|
|
cJSON *json = cJSON_Parse(buf);
|
|
if (!json) return ESP_FAIL;
|
|
|
|
// Valores padrão
|
|
bool enabled = false;
|
|
const char *ssid = NULL;
|
|
const char *password = NULL;
|
|
|
|
cJSON *j_enabled = cJSON_GetObjectItem(json, "enabled");
|
|
if (cJSON_IsBool(j_enabled)) enabled = j_enabled->valueint;
|
|
|
|
cJSON *j_ssid = cJSON_GetObjectItem(json, "ssid");
|
|
if (cJSON_IsString(j_ssid)) ssid = j_ssid->valuestring;
|
|
|
|
cJSON *j_password = cJSON_GetObjectItem(json, "password");
|
|
if (cJSON_IsString(j_password)) password = j_password->valuestring;
|
|
|
|
// Enviar resposta antes de alterar Wi-Fi
|
|
httpd_resp_sendstr(req, "Wi-Fi config atualizada com sucesso");
|
|
|
|
// Alocar struct para passar para a task
|
|
wifi_task_data_t *task_data = malloc(sizeof(wifi_task_data_t));
|
|
if (!task_data) {
|
|
cJSON_Delete(json);
|
|
ESP_LOGE(TAG, "Memory allocation failed for Wi-Fi task");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
task_data->enabled = enabled;
|
|
strncpy(task_data->ssid, ssid ? ssid : "", sizeof(task_data->ssid));
|
|
strncpy(task_data->password, password ? password : "", sizeof(task_data->password));
|
|
|
|
// Criar task normal com função C
|
|
xTaskCreate(
|
|
wifi_apply_config_task,
|
|
"wifi_config_task",
|
|
4096,
|
|
task_data,
|
|
3,
|
|
NULL
|
|
);
|
|
|
|
cJSON_Delete(json);
|
|
return ESP_OK;
|
|
}
|
|
|
|
|
|
static esp_err_t config_mqtt_get_handler(httpd_req_t *req)
|
|
{
|
|
ESP_LOGI(TAG, "Handling GET /api/v1/config/mqtt");
|
|
|
|
httpd_resp_set_type(req, "application/json");
|
|
|
|
bool enabled = mqtt_get_enabled();
|
|
char server[64] = {0};
|
|
char base_topic[32] = {0};
|
|
char username[32] = {0};
|
|
char password[64] = {0};
|
|
uint16_t periodicity = mqtt_get_periodicity();
|
|
|
|
mqtt_get_server(server);
|
|
mqtt_get_base_topic(base_topic);
|
|
mqtt_get_user(username);
|
|
mqtt_get_password(password);
|
|
|
|
ESP_LOGI(TAG, "MQTT Config:");
|
|
ESP_LOGI(TAG, " Enabled: %s", enabled ? "true" : "false");
|
|
ESP_LOGI(TAG, " Server: %s", server);
|
|
ESP_LOGI(TAG, " Topic: %s", base_topic);
|
|
ESP_LOGI(TAG, " Username: %s", username);
|
|
ESP_LOGI(TAG, " Password: %s", password);
|
|
ESP_LOGI(TAG, " Periodicity: %d", periodicity);
|
|
|
|
cJSON *config = cJSON_CreateObject();
|
|
cJSON_AddBoolToObject(config, "enabled", enabled);
|
|
cJSON_AddStringToObject(config, "host", server);
|
|
cJSON_AddNumberToObject(config, "port", 1883);
|
|
cJSON_AddStringToObject(config, "username", username);
|
|
cJSON_AddStringToObject(config, "password", password);
|
|
cJSON_AddStringToObject(config, "topic", base_topic);
|
|
cJSON_AddNumberToObject(config, "periodicity", periodicity);
|
|
|
|
const char *config_str = cJSON_Print(config);
|
|
httpd_resp_sendstr(req, config_str);
|
|
|
|
free((void *)config_str);
|
|
cJSON_Delete(config);
|
|
return ESP_OK;
|
|
}
|
|
|
|
|
|
static esp_err_t config_mqtt_post_handler(httpd_req_t *req)
|
|
{
|
|
ESP_LOGI(TAG, "Handling POST /api/v1/config/mqtt");
|
|
|
|
char buf[512];
|
|
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
|
|
if (len <= 0) {
|
|
ESP_LOGE(TAG, "Failed to read request body");
|
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
|
|
return ESP_FAIL;
|
|
}
|
|
buf[len] = '\0';
|
|
ESP_LOGI(TAG, "Received JSON: %s", buf);
|
|
|
|
cJSON *json = cJSON_Parse(buf);
|
|
if (!json) {
|
|
ESP_LOGE(TAG, "Invalid JSON format");
|
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
bool enabled = false;
|
|
const char *host = NULL, *topic = NULL, *username = NULL, *password = NULL;
|
|
int periodicity = 30;
|
|
|
|
if (cJSON_IsBool(cJSON_GetObjectItem(json, "enabled")))
|
|
enabled = cJSON_GetObjectItem(json, "enabled")->valueint;
|
|
|
|
cJSON *j_host = cJSON_GetObjectItem(json, "host");
|
|
if (cJSON_IsString(j_host)) host = j_host->valuestring;
|
|
|
|
cJSON *j_topic = cJSON_GetObjectItem(json, "topic");
|
|
if (cJSON_IsString(j_topic)) topic = j_topic->valuestring;
|
|
|
|
cJSON *j_user = cJSON_GetObjectItem(json, "username");
|
|
if (cJSON_IsString(j_user)) username = j_user->valuestring;
|
|
|
|
cJSON *j_pass = cJSON_GetObjectItem(json, "password");
|
|
if (cJSON_IsString(j_pass)) password = j_pass->valuestring;
|
|
|
|
cJSON *j_periodicity = cJSON_GetObjectItem(json, "periodicity");
|
|
if (cJSON_IsNumber(j_periodicity)) periodicity = j_periodicity->valueint;
|
|
|
|
ESP_LOGI(TAG, "Applying MQTT config:");
|
|
ESP_LOGI(TAG, " Enabled: %s", enabled ? "true" : "false");
|
|
ESP_LOGI(TAG, " Host: %s", host);
|
|
ESP_LOGI(TAG, " Topic: %s", topic);
|
|
ESP_LOGI(TAG, " Username: %s", username);
|
|
ESP_LOGI(TAG, " Password: %s", password);
|
|
ESP_LOGI(TAG, " Periodicity: %d", periodicity);
|
|
|
|
esp_err_t err = mqtt_set_config(enabled, host, topic, username, password, periodicity);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to apply MQTT config (code %d)", err);
|
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to apply config");
|
|
cJSON_Delete(json);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
httpd_resp_sendstr(req, "Configuração MQTT atualizada com sucesso");
|
|
cJSON_Delete(json);
|
|
return ESP_OK;
|
|
}
|
|
|
|
|
|
|
|
void register_network_handlers(httpd_handle_t server, void *ctx) {
|
|
httpd_uri_t wifi_get = {
|
|
.uri = "/api/v1/config/wifi",
|
|
.method = HTTP_GET,
|
|
.handler = wifi_get_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &wifi_get);
|
|
|
|
httpd_uri_t wifi_post = {
|
|
.uri = "/api/v1/config/wifi",
|
|
.method = HTTP_POST,
|
|
.handler = wifi_post_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &wifi_post);
|
|
|
|
// URI handler for getting MQTT config
|
|
httpd_uri_t config_mqtt_get_uri = {
|
|
.uri = "/api/v1/config/mqtt",
|
|
.method = HTTP_GET,
|
|
.handler = config_mqtt_get_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &config_mqtt_get_uri);
|
|
|
|
// URI handler for posting MQTT config
|
|
httpd_uri_t config_mqtt_post_uri = {
|
|
.uri = "/api/v1/config/mqtt",
|
|
.method = HTTP_POST,
|
|
.handler = config_mqtt_post_handler,
|
|
.user_ctx = ctx
|
|
};
|
|
httpd_register_uri_handler(server, &config_mqtt_post_uri);
|
|
}
|
|
|
|
// === Fim de: components/rest_api/src/network_api.c ===
|