This commit is contained in:
2025-08-24 11:17:48 +01:00
parent 0d0dc5b129
commit 96b2ab1f57
31 changed files with 2883 additions and 4054 deletions

View File

@@ -1,5 +1,5 @@
// =========================
// auth_api.c
// auth_api.c (nova interface por modo)
// =========================
#include "auth_api.h"
@@ -16,60 +16,101 @@ static const char *TAG = "auth_api";
static struct {
char username[128];
} users[10] = { /* {"admin"}, {"user1"} */ };
} users[10] = { {"admin"}, {"user1"} };
static int num_users = 2;
// =================================
// Handlers for Auth Methods (RFID)
// Helpers
// =================================
static esp_err_t auth_methods_get_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "application/json");
cJSON *json = cJSON_CreateObject();
cJSON_AddBoolToObject(json, "RFID", auth_is_enabled());
static void send_json(httpd_req_t *req, cJSON *json) {
char *str = cJSON_PrintUnformatted(json);
httpd_resp_sendstr(req, str);
free(str);
httpd_resp_set_type(req, "application/json");
httpd_resp_sendstr(req, str ? str : "{}");
if (str) free(str);
cJSON_Delete(json);
}
static esp_err_t recv_body(httpd_req_t *req, char *buf, size_t buf_sz, int *out_len) {
int remaining = req->content_len;
int received = 0;
if (remaining <= 0) {
*out_len = 0;
return ESP_OK;
}
while (remaining > 0 && received < (int)(buf_sz - 1)) {
int chunk = remaining;
int space = (int)(buf_sz - 1 - received);
if (chunk > space) chunk = space;
int ret = httpd_req_recv(req, buf + received, chunk);
if (ret <= 0) return ESP_FAIL;
received += ret;
remaining -= ret;
}
buf[received] = '\0';
*out_len = received;
return ESP_OK;
}
static esp_err_t auth_methods_post_handler(httpd_req_t *req) {
// =================================
// Auth Mode (NEW API)
// =================================
static esp_err_t auth_mode_get_handler(httpd_req_t *req) {
auth_mode_t mode = auth_get_mode();
cJSON *json = cJSON_CreateObject();
cJSON_AddStringToObject(json, "mode", auth_mode_to_str(mode));
send_json(req, json);
return ESP_OK;
}
static esp_err_t auth_mode_post_handler(httpd_req_t *req) {
char buf[256];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
int len = 0;
if (recv_body(req, buf, sizeof(buf), &len) != ESP_OK) {
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao receber dados");
return ESP_FAIL;
}
buf[len] = '\0';
cJSON *json = cJSON_Parse(buf);
cJSON *json = cJSON_ParseWithLength(buf, len);
if (!json) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "JSON inválido");
return ESP_FAIL;
}
cJSON *rfid = cJSON_GetObjectItem(json, "RFID");
if (rfid && cJSON_IsBool(rfid)) {
auth_set_enabled(cJSON_IsTrue(rfid));
} else {
cJSON *mode_js = cJSON_GetObjectItem(json, "mode");
if (!cJSON_IsString(mode_js) || mode_js->valuestring == NULL) {
cJSON_Delete(json);
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Campo 'RFID' inválido ou ausente");
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Campo 'mode' inválido ou ausente");
return ESP_FAIL;
}
auth_mode_t mode;
if (!auth_mode_from_str(mode_js->valuestring, &mode)) {
cJSON_Delete(json);
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Valor de 'mode' inválido (use: open|local|ocpp)");
return ESP_FAIL;
}
auth_set_mode(mode);
cJSON_Delete(json);
httpd_resp_sendstr(req, "Métodos de autenticação atualizados");
cJSON *resp = cJSON_CreateObject();
cJSON_AddStringToObject(resp, "mode", auth_mode_to_str(mode));
send_json(req, resp);
return ESP_OK;
}
// =================================
// User Management Handlers
/* Users (mock) */
// =================================
static esp_err_t users_get_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "application/json");
cJSON *root = cJSON_CreateObject();
cJSON *list = cJSON_CreateArray();
for (int i = 0; i < num_users; ++i) {
@@ -78,28 +119,27 @@ static esp_err_t users_get_handler(httpd_req_t *req) {
cJSON_AddItemToArray(list, u);
}
cJSON_AddItemToObject(root, "users", list);
char *str = cJSON_PrintUnformatted(root);
httpd_resp_sendstr(req, str);
free(str);
cJSON_Delete(root);
send_json(req, root);
return ESP_OK;
}
static esp_err_t users_post_handler(httpd_req_t *req) {
char buf[128];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) return ESP_FAIL;
buf[len] = '\0';
int len = 0;
if (recv_body(req, buf, sizeof(buf), &len) != ESP_OK || len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Body vazio");
return ESP_FAIL;
}
if (num_users < 10) {
strlcpy(users[num_users].username, buf, sizeof(users[num_users].username));
num_users++;
httpd_resp_sendstr(req, "Usuário adicionado com sucesso");
return ESP_OK;
} else {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Limite de usuários atingido");
return ESP_FAIL;
}
return ESP_OK;
}
static esp_err_t users_delete_handler(httpd_req_t *req) {
@@ -124,27 +164,21 @@ static esp_err_t users_delete_handler(httpd_req_t *req) {
}
// =================================
// Tag Management Handlers
// Tags (apenas úteis no modo LOCAL)
// =================================
static esp_err_t tags_get_handler(httpd_req_t *req) {
httpd_resp_set_type(req, "application/json");
cJSON *root = cJSON_CreateObject();
cJSON *list = cJSON_CreateArray();
int count = auth_get_tag_count();
for (int i = 0; i < count; i++) {
const char *tag = auth_get_tag_by_index(i);
if (tag) {
cJSON_AddItemToArray(list, cJSON_CreateString(tag));
}
if (tag) cJSON_AddItemToArray(list, cJSON_CreateString(tag));
}
cJSON_AddItemToObject(root, "tags", list);
char *str = cJSON_PrintUnformatted(root);
httpd_resp_sendstr(req, str);
free(str);
cJSON_Delete(root);
send_json(req, root);
return ESP_OK;
}
@@ -164,6 +198,10 @@ static esp_err_t tags_delete_handler(httpd_req_t *req) {
}
static esp_err_t tags_register_handler(httpd_req_t *req) {
if (auth_get_mode() != AUTH_MODE_LOCAL_RFID) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Registo de tags disponível apenas no modo LOCAL");
return ESP_FAIL;
}
auth_wait_for_tag_registration();
httpd_resp_sendstr(req, "Modo de registro de tag ativado");
return ESP_OK;
@@ -174,21 +212,21 @@ static esp_err_t tags_register_handler(httpd_req_t *req) {
// =================================
void register_auth_handlers(httpd_handle_t server, void *ctx) {
// Auth methods
// Auth mode
httpd_register_uri_handler(server, &(httpd_uri_t){
.uri = "/api/v1/config/auth-methods",
.uri = "/api/v1/config/auth-mode",
.method = HTTP_GET,
.handler = auth_methods_get_handler,
.handler = auth_mode_get_handler,
.user_ctx = ctx
});
httpd_register_uri_handler(server, &(httpd_uri_t){
.uri = "/api/v1/config/auth-methods",
.uri = "/api/v1/config/auth-mode",
.method = HTTP_POST,
.handler = auth_methods_post_handler,
.handler = auth_mode_post_handler,
.user_ctx = ctx
});
// Users
// Users (mock)
httpd_register_uri_handler(server, &(httpd_uri_t){
.uri = "/api/v1/config/users",
.method = HTTP_GET,

View File

@@ -1,45 +1,63 @@
// =========================
// ocpp_api.c
// =========================
#include "ocpp_api.h"
#include "ocpp.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_http_server.h"
#include "cJSON.h"
#include <string.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) {
ESP_LOGD(TAG, "GET /api/v1/ocpp");
httpd_resp_set_type(req, "application/json");
char server[64] = {0};
char charge_id[64] = {0};
ocpp_get_server(server);
ocpp_get_charge_id(charge_id);
cJSON *status = cJSON_CreateObject();
cJSON_AddStringToObject(status, "status", "connected");
char *str = cJSON_Print(status);
cJSON_AddBoolToObject(status, "connected", ocpp_is_connected());
cJSON_AddStringToObject(status, "server", server);
cJSON_AddStringToObject(status, "charge_id", charge_id);
char *str = cJSON_PrintUnformatted(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) {
ESP_LOGD(TAG, "GET /api/v1/config/ocpp");
httpd_resp_set_type(req, "application/json");
char server[64] = {0};
char charge_id[64] = {0};
bool enabled = ocpp_get_enabled();
ocpp_get_server(server);
ocpp_get_charge_id(charge_id);
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);
cJSON_AddBoolToObject(json, "enabled", enabled);
cJSON_AddStringToObject(json, "url", server);
cJSON_AddStringToObject(json, "chargeBoxId", charge_id);
char *str = cJSON_PrintUnformatted(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) {
ESP_LOGD(TAG, "POST /api/v1/config/ocpp");
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
@@ -47,19 +65,28 @@ static esp_err_t ocpp_post_config_handler(httpd_req_t *req) {
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 *enabled = cJSON_GetObjectItem(json, "enabled");
if (cJSON_IsBool(enabled)) {
ocpp_set_enabled(cJSON_IsTrue(enabled));
}
cJSON *url = cJSON_GetObjectItem(json, "url");
if (url) strlcpy(ocpp_config.url, url->valuestring, sizeof(ocpp_config.url));
if (cJSON_IsString(url)) {
ocpp_set_server(url->valuestring);
}
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));
if (cJSON_IsString(id)) {
ocpp_set_charge_id(id->valuestring);
}
cJSON_Delete(json);
httpd_resp_sendstr(req, "OCPP config atualizada com sucesso");
return ESP_OK;

View File

@@ -13,8 +13,8 @@
}
</style>
<title>Vite + React</title>
<script type="module" crossorigin src="/assets/index-ClgQvp_F.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-AuNGQ-2m.css">
<script type="module" crossorigin src="/assets/index-CmjuW5AW.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Bc9ibDeR.css">
</head>
<body>
<div id="root"></div>