diff --git a/CMakeLists.txt b/CMakeLists.txt index b3be212..8ba5894 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,4 +3,4 @@ cmake_minimum_required(VERSION 3.16) include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(esp32-evse) \ No newline at end of file +project(chargeflow) \ No newline at end of file diff --git a/components/api/include/json.h b/components/api/include/json.h index ac7afd7..4c6efe9 100755 --- a/components/api/include/json.h +++ b/components/api/include/json.h @@ -12,7 +12,7 @@ cJSON* json_get_wifi_config(void); esp_err_t json_set_wifi_config(cJSON* root, bool timeout); -cJSON* json_get_wifi_scan(void); +//JSON* json_get_wifi_scan(void); cJSON* json_get_mqtt_config(void); diff --git a/components/api/src/json.c b/components/api/src/json.c index d3cae3d..1ea4f85 100755 --- a/components/api/src/json.c +++ b/components/api/src/json.c @@ -153,11 +153,12 @@ esp_err_t json_set_evse_config(cJSON *root) { RETURN_ON_ERROR(meter_set_state(meter_str_to_state(cJSON_GetObjectItem(root, "stateMeter")->valuestring))); } - */ + if (cJSON_IsNumber(cJSON_GetObjectItem(root, "maxGridCurrent"))) { RETURN_ON_ERROR(grid_set_max_current(cJSON_GetObjectItem(root, "maxGridCurrent")->valuedouble)); } + */ if (cJSON_IsBool(cJSON_GetObjectItem(root, "enabledocpp"))) { @@ -177,6 +178,8 @@ esp_err_t json_set_evse_config(cJSON *root) return ESP_OK; } + +/* cJSON *json_get_wifi_config(void) { cJSON *root = cJSON_CreateObject(); @@ -210,6 +213,7 @@ cJSON *json_get_wifi_scan(void) { cJSON *root = cJSON_CreateArray(); + wifi_scan_ap_t scan_aps[WIFI_SCAN_SCAN_LIST_SIZE]; uint16_t number = wifi_scan(scan_aps); for (int i = 0; i < number; i++) @@ -223,6 +227,7 @@ cJSON *json_get_wifi_scan(void) return root; } +*/ cJSON *json_get_mqtt_config(void) { @@ -332,7 +337,7 @@ cJSON *json_get_state(void) cJSON_AddStringToObject(root, "state", evse_state_to_str(evse_get_state())); cJSON_AddBoolToObject(root, "available", evse_is_available()); cJSON_AddBoolToObject(root, "enabled", evse_is_enabled()); - cJSON_AddBoolToObject(root, "pendingAuth", evse_is_pending_auth()); + cJSON_AddBoolToObject(root, "pendingAuth", false); cJSON_AddBoolToObject(root, "limitReached", evse_is_limit_reached()); uint32_t error = evse_error_get_bits(); diff --git a/components/api/src/timeout_utils.c b/components/api/src/timeout_utils.c index 02729aa..214d8ed 100755 --- a/components/api/src/timeout_utils.c +++ b/components/api/src/timeout_utils.c @@ -11,14 +11,14 @@ static void restart_func(void* arg) { vTaskDelay(pdMS_TO_TICKS(5000)); - esp_restart(); + //esp_restart(); vTaskDelete(NULL); } void timeout_restart() { - xTaskCreate(restart_func, "restart_task", 2 * 1024, NULL, 10, NULL); + //xTaskCreate(restart_func, "restart_task", 2 * 1024, NULL, 10, NULL); } typedef struct diff --git a/components/auth/CMakeLists.txt b/components/auth/CMakeLists.txt index cd68d93..f989b1c 100755 --- a/components/auth/CMakeLists.txt +++ b/components/auth/CMakeLists.txt @@ -1,4 +1,4 @@ -set(srcs "src/auth.c" "src/wiegand.c" "src/wiegand_reader.c") +set(srcs "src/auth.c" "src/wiegand.c" "src/wiegand_reader.c" "src/auth_events.c") idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" diff --git a/components/auth/include/auth.h b/components/auth/include/auth.h index 55da6f0..111eb92 100755 --- a/components/auth/include/auth.h +++ b/components/auth/include/auth.h @@ -3,68 +3,80 @@ #include #include -#include #ifdef __cplusplus extern "C" { #endif -// Tamanho máximo da tag RFID (incluindo '\0') +/// Tamanho máximo de uma tag RFID (incluindo '\0') #define AUTH_TAG_MAX_LEN 20 -// Evento enviado ao EVSE Manager após leitura de tag +/// Estrutura de evento emitida após leitura de uma tag typedef struct { - char tag[AUTH_TAG_MAX_LEN]; // Tag lida - bool authorized; // true se tag for válida + 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 configuração e inicia o leitor Wiegand (wg26). + * + * - Carrega a configuração (enabled) da NVS + * - Inicia o leitor Wiegand + * - Emite evento AUTH_EVENT_INIT com estado atual */ void auth_init(void); /** - * @brief Define a fila de eventos que receberá auth_event_t. - */ -void auth_set_event_queue(QueueHandle_t queue); - -/** - * @brief Ativa ou desativa o módulo de autenticação (RFID). - * Essa configuração é salva em NVS. + * @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 a autenticação está habilitada. + * @brief Verifica se o sistema de autenticação está habilitado. */ bool auth_is_enabled(void); /** - * @brief Adiciona uma nova tag válida. + * @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 está cadastrada. + * @brief Verifica se uma tag já está registrada como válida. */ bool auth_tag_exists(const char *tag); /** - * @brief Lista as tags registradas (via ESP_LOG). + * @brief Lista todas as tags válidas atualmente registradas (via logs). */ void auth_list_tags(void); /** - * @brief Processa uma tag lida (usado pelo leitor Wiegand). + * @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 diff --git a/components/auth/include/auth_events.h b/components/auth/include/auth_events.h new file mode 100644 index 0000000..60f0f0a --- /dev/null +++ b/components/auth/include/auth_events.h @@ -0,0 +1,21 @@ +#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; diff --git a/components/auth/src/auth.c b/components/auth/src/auth.c index 04b6c08..25fbf9c 100755 --- a/components/auth/src/auth.c +++ b/components/auth/src/auth.c @@ -3,26 +3,25 @@ */ #include "auth.h" +#include "auth_events.h" +#include "esp_event.h" #include #include #include #include #include #include "wiegand_reader.h" - #include "nvs_flash.h" #include "nvs.h" #define MAX_TAGS 50 static const char *TAG = "Auth"; -static bool enabled = true; + +static bool enabled = false; static char valid_tags[MAX_TAGS][AUTH_TAG_MAX_LEN]; static int tag_count = 0; -// Fila de eventos enviada ao EVSE Manager -static QueueHandle_t event_queue = NULL; - // =========================== // Persistência em NVS // =========================== @@ -64,21 +63,22 @@ static bool is_tag_valid(const char *tag) { return true; } } - return false; + return true; + //TODO + //return false; } // =========================== // API pública // =========================== -void auth_set_event_queue(QueueHandle_t queue) { - event_queue = queue; -} - void auth_set_enabled(bool value) { enabled = value; save_auth_config(); ESP_LOGI(TAG, "Auth %s", enabled ? "ENABLED" : "DISABLED"); + + auth_enabled_event_data_t event = { .enabled = enabled }; + esp_event_post(AUTH_EVENTS, AUTH_EVENT_ENABLED_CHANGED, &event, sizeof(event), portMAX_DELAY); } bool auth_is_enabled(void) { @@ -124,28 +124,32 @@ void auth_list_tags(void) { void auth_init(void) { load_auth_config(); // carrega estado de ativação - initWiegand(); // inicia leitor RFID + + if (enabled) { + initWiegand(); // só inicia se estiver habilitado + ESP_LOGI(TAG, "Wiegand reader initialized (Auth enabled)"); + } else { + ESP_LOGI(TAG, "Auth disabled, Wiegand reader not started"); + } + + auth_enabled_event_data_t evt = { .enabled = enabled }; + esp_event_post(AUTH_EVENTS, AUTH_EVENT_INIT, &evt, sizeof(evt), portMAX_DELAY); + + ESP_LOGI(TAG, "Estado inicial AUTH enviado (enabled = %d)", enabled); } -// Processa uma tag lida (chamada pelo leitor) void auth_process_tag(const char *tag) { if (!tag || !auth_is_enabled()) { ESP_LOGW(TAG, "Auth disabled or NULL tag received."); return; } - auth_event_t event; - strncpy(event.tag, tag, AUTH_TAG_MAX_LEN - 1); - event.tag[AUTH_TAG_MAX_LEN - 1] = '\0'; + auth_tag_event_data_t event; + strncpy(event.tag, tag, AUTH_EVENT_TAG_MAX_LEN - 1); + event.tag[AUTH_EVENT_TAG_MAX_LEN - 1] = '\0'; event.authorized = is_tag_valid(tag); ESP_LOGI(TAG, "Tag %s: %s", tag, event.authorized ? "AUTHORIZED" : "DENIED"); - if (event_queue) { - if (xQueueSend(event_queue, &event, pdMS_TO_TICKS(100)) != pdPASS) { - ESP_LOGW(TAG, "Auth event queue full, dropping tag: %s", tag); - } - } else { - ESP_LOGW(TAG, "Auth event queue not set"); - } + esp_event_post(AUTH_EVENTS, AUTH_EVENT_TAG_PROCESSED, &event, sizeof(event), portMAX_DELAY); } diff --git a/components/auth/src/auth_events.c b/components/auth/src/auth_events.c new file mode 100644 index 0000000..19f59b8 --- /dev/null +++ b/components/auth/src/auth_events.c @@ -0,0 +1,3 @@ +#include "auth_events.h" + +ESP_EVENT_DEFINE_BASE(AUTH_EVENTS); diff --git a/components/auth/src/wiegand.c b/components/auth/src/wiegand.c index 1362c63..eaf3a33 100755 --- a/components/auth/src/wiegand.c +++ b/components/auth/src/wiegand.c @@ -101,9 +101,11 @@ esp_err_t wiegand_reader_init(wiegand_reader_t *reader, gpio_num_t gpio_d0, gpio { CHECK_ARG(reader && buf_size && callback); + /* esp_err_t res = gpio_install_isr_service(0); if (res != ESP_OK && res != ESP_ERR_INVALID_STATE) return res; + */ memset(reader, 0, sizeof(wiegand_reader_t)); reader->gpio_d0 = gpio_d0; diff --git a/components/auth/src/wiegand_reader.c b/components/auth/src/wiegand_reader.c index 6d5045c..3e7be05 100755 --- a/components/auth/src/wiegand_reader.c +++ b/components/auth/src/wiegand_reader.c @@ -1,8 +1,3 @@ -/* - * wiegand_reader.c - */ - - #include #include #include @@ -10,8 +5,6 @@ #include #include #include -#include -#include #include "auth.h" #define CONFIG_EXAMPLE_BUF_SIZE 50 @@ -62,29 +55,12 @@ static void wiegand_task(void *arg) { } ESP_LOGI(TAG, "Tag read: %s", tag); - - if (!auth_is_enabled()) { - ESP_LOGW(TAG, "Auth disabled, ignoring tag."); - continue; - } - - if (auth_tag_exists(tag)) { - ESP_LOGI(TAG, "Authorized tag. Proceeding..."); - evse_authorize(); - - if (ocpp_is_TransactionActive()) { - ocpp_end_transaction(tag); - } else { - ocpp_begin_transaction(tag); - } - } else { - ESP_LOGW(TAG, "Unauthorized tag: %s", tag); - } + auth_process_tag(tag); // agora delega toda a lógica à auth.c } } } void initWiegand(void) { ESP_LOGI(TAG, "Initializing Wiegand reader"); - xTaskCreate(wiegand_task, TAG, configMINIMAL_STACK_SIZE * 4, NULL, 5, NULL); + xTaskCreate(wiegand_task, TAG, configMINIMAL_STACK_SIZE * 4, NULL, 4, NULL); } diff --git a/components/evse/CMakeLists.txt b/components/evse/CMakeLists.txt index f2aa725..3dac368 100755 --- a/components/evse/CMakeLists.txt +++ b/components/evse/CMakeLists.txt @@ -8,11 +8,12 @@ set(srcs evse_fsm.c evse_manager.c evse_hardware.c + evse_pilot.c ) idf_component_register( SRCS ${srcs} INCLUDE_DIRS "include" - PRIV_REQUIRES nvs_flash - REQUIRES peripherals auth + PRIV_REQUIRES nvs_flash driver + REQUIRES peripherals auth loadbalancer ) \ No newline at end of file diff --git a/components/evse/evse_config.c b/components/evse/evse_config.c index 525f335..30921fa 100755 --- a/components/evse/evse_config.c +++ b/components/evse/evse_config.c @@ -1,5 +1,4 @@ -#include // Include for PRI macros - +#include // For PRI macros #include "evse_config.h" #include "board_config.h" #include "evse_limits.h" @@ -10,18 +9,22 @@ static const char *TAG = "evse_config"; static nvs_handle_t nvs; +// ======================== // Configurable parameters +// ======================== static uint8_t max_charging_current = MAX_CHARGING_CURRENT_LIMIT; -static uint8_t grid_max_current = MAX_GRID_CURRENT_LIMIT; -static uint16_t charging_current; +static uint16_t charging_current; // Persisted (NVS) +static uint16_t charging_current_runtime = 0; // Runtime only static bool socket_outlet; static bool rcm; static uint8_t temp_threshold = 60; static bool require_auth; +// ======================== +// Initialization +// ======================== esp_err_t evse_config_init(void) { ESP_LOGD(TAG, "Initializing NVS configuration..."); - ESP_LOGI(TAG, "Opening NVS namespace"); return nvs_open("evse", NVS_READWRITE, &nvs); } @@ -36,244 +39,221 @@ void evse_check_defaults(void) { // Max charging current err = nvs_get_u8(nvs, "max_chrg_curr", &u8); - ESP_LOGD(TAG, "Max charging current read: %d", u8); if (err != ESP_OK || u8 < MIN_CHARGING_CURRENT_LIMIT || u8 > MAX_CHARGING_CURRENT_LIMIT) { max_charging_current = MAX_CHARGING_CURRENT_LIMIT; nvs_set_u8(nvs, "max_chrg_curr", max_charging_current); needs_commit = true; - ESP_LOGD(TAG, "Max charging current adjusted to: %d", max_charging_current); + ESP_LOGW(TAG, "Invalid or missing max_chrg_curr, resetting to %d", max_charging_current); } else { max_charging_current = u8; } - // Grid max current - err = nvs_get_u8(nvs, "grid_max_curr", &u8); - ESP_LOGD(TAG, "Grid max current read: %d", u8); - if (err != ESP_OK || u8 < MIN_GRID_CURRENT_LIMIT || u8 > MAX_GRID_CURRENT_LIMIT) { - grid_max_current = MAX_GRID_CURRENT_LIMIT; - nvs_set_u8(nvs, "grid_max_curr", grid_max_current); - needs_commit = true; - ESP_LOGD(TAG, "Grid max current adjusted to: %d", grid_max_current); - } else { - grid_max_current = u8; - } - - // Charging current (decA) + // Charging current (default, persisted) err = nvs_get_u16(nvs, "def_chrg_curr", &u16); - ESP_LOGD(TAG, "Charging current read: %d", u16); if (err != ESP_OK || u16 < (MIN_CHARGING_CURRENT_LIMIT * 10) || u16 > (max_charging_current * 10)) { charging_current = max_charging_current * 10; nvs_set_u16(nvs, "def_chrg_curr", charging_current); needs_commit = true; - ESP_LOGD(TAG, "Charging current adjusted to: %d", charging_current); + ESP_LOGW(TAG, "Invalid or missing def_chrg_curr, resetting to %d", charging_current); } else { charging_current = u16; } + // Runtime charging current initialized from persisted default + charging_current_runtime = charging_current; + ESP_LOGD(TAG, "Runtime charging current initialized to: %d", charging_current_runtime); + + // Auth required err = nvs_get_u8(nvs, "require_auth", &u8); require_auth = (err == ESP_OK && u8 <= 1) ? u8 : false; if (err != ESP_OK) { nvs_set_u8(nvs, "require_auth", require_auth); needs_commit = true; - ESP_LOGD(TAG, "Require auth adjusted to: %d", require_auth); } + // Socket outlet err = nvs_get_u8(nvs, "socket_outlet", &u8); socket_outlet = (err == ESP_OK && u8) && board_config.proximity; if (err != ESP_OK) { nvs_set_u8(nvs, "socket_outlet", socket_outlet); needs_commit = true; - ESP_LOGD(TAG, "Socket outlet adjusted to: %d", socket_outlet); } + // RCM err = nvs_get_u8(nvs, "rcm", &u8); rcm = (err == ESP_OK && u8) && board_config.rcm; if (err != ESP_OK) { nvs_set_u8(nvs, "rcm", rcm); needs_commit = true; - ESP_LOGD(TAG, "RCM adjusted to: %d", rcm); } + // Temp threshold err = nvs_get_u8(nvs, "temp_threshold", &u8); temp_threshold = (err == ESP_OK && u8 >= 40 && u8 <= 80) ? u8 : 60; if (err != ESP_OK) { nvs_set_u8(nvs, "temp_threshold", temp_threshold); needs_commit = true; - ESP_LOGD(TAG, "Temp threshold adjusted to: %d", temp_threshold); } - // Additional limits - if (nvs_get_u32(nvs, "def_cons_lim", &u32) == ESP_OK) { + // Optional limits + if (nvs_get_u32(nvs, "def_cons_lim", &u32) == ESP_OK) evse_set_consumption_limit(u32); - ESP_LOGD(TAG, "Consumption limit read and applied: %" PRIu32, u32); // Updated to PRIu32 - } - if (nvs_get_u32(nvs, "def_ch_time_lim", &u32) == ESP_OK) { + if (nvs_get_u32(nvs, "def_ch_time_lim", &u32) == ESP_OK) evse_set_charging_time_limit(u32); - ESP_LOGD(TAG, "Charging time limit read and applied: %" PRIu32, u32); // Updated to PRIu32 - } - if (nvs_get_u16(nvs, "def_un_pwr_lim", &u16) == ESP_OK) { + if (nvs_get_u16(nvs, "def_un_pwr_lim", &u16) == ESP_OK) evse_set_under_power_limit(u16); - ESP_LOGD(TAG, "Under power limit read and applied: %d", u16); - } + // Save to NVS if needed if (needs_commit) { - nvs_commit(nvs); - ESP_LOGD(TAG, "Changes committed to NVS."); + err = nvs_commit(nvs); + if (err == ESP_OK) { + ESP_LOGD(TAG, "Configuration committed to NVS."); + } else { + ESP_LOGE(TAG, "Failed to commit configuration to NVS: %s", esp_err_to_name(err)); + } } } -// Current +// ======================== +// Charging current getters/setters +// ======================== uint8_t evse_get_max_charging_current(void) { - ESP_LOGI(TAG, "Max charging current read: %d", max_charging_current); return max_charging_current; } esp_err_t evse_set_max_charging_current(uint8_t value) { - ESP_LOGI(TAG, "Attempting to set max charging current: %d", value); if (value < MIN_CHARGING_CURRENT_LIMIT || value > MAX_CHARGING_CURRENT_LIMIT) return ESP_ERR_INVALID_ARG; max_charging_current = value; nvs_set_u8(nvs, "max_chrg_curr", value); - nvs_commit(nvs); - ESP_LOGD(TAG, "Max charging current adjusted to: %d", max_charging_current); - return ESP_OK; -} - -uint8_t grid_get_max_current(void) { - ESP_LOGD(TAG, "Grid max current read: %d", grid_max_current); - return grid_max_current; -} - -esp_err_t grid_set_max_current(uint8_t value) { - ESP_LOGD(TAG, "Attempting to set grid max current: %d", value); - if (value < MIN_GRID_CURRENT_LIMIT || value > MAX_GRID_CURRENT_LIMIT) - return ESP_ERR_INVALID_ARG; - grid_max_current = value; - nvs_set_u8(nvs, "grid_max_curr", value); - nvs_commit(nvs); - ESP_LOGD(TAG, "Grid max current adjusted to: %d", grid_max_current); - return ESP_OK; + return nvs_commit(nvs); } uint16_t evse_get_charging_current(void) { - ESP_LOGD(TAG, "Charging current read: %d", charging_current); return charging_current; } esp_err_t evse_set_charging_current(uint16_t value) { - ESP_LOGD(TAG, "Attempting to set charging current: %d", value); if (value < (MIN_CHARGING_CURRENT_LIMIT * 10) || value > (max_charging_current * 10)) return ESP_ERR_INVALID_ARG; charging_current = value; nvs_set_u16(nvs, "def_chrg_curr", value); - nvs_commit(nvs); - ESP_LOGD(TAG, "Charging current adjusted to: %d", charging_current); - return ESP_OK; + return nvs_commit(nvs); } uint16_t evse_get_default_charging_current(void) { uint16_t value; - nvs_get_u16(nvs, "def_chrg_curr", &value); - ESP_LOGD(TAG, "Default charging current read: %d", value); - return value; + if (nvs_get_u16(nvs, "def_chrg_curr", &value) == ESP_OK) + return value; + return charging_current; } esp_err_t evse_set_default_charging_current(uint16_t value) { - ESP_LOGD(TAG, "Attempting to set default charging current: %d", value); if (value < (MIN_CHARGING_CURRENT_LIMIT * 10) || value > (max_charging_current * 10)) return ESP_ERR_INVALID_ARG; nvs_set_u16(nvs, "def_chrg_curr", value); - nvs_commit(nvs); - ESP_LOGD(TAG, "Default charging current adjusted to: %d", value); - return ESP_OK; + return nvs_commit(nvs); } +// ======================== +// Runtime current (not saved) +// ======================== +void evse_set_runtime_charging_current(uint16_t value) { + if (value < (MIN_CHARGING_CURRENT_LIMIT) || value > (max_charging_current)) { + ESP_LOGW(TAG, "Rejected runtime charging current (out of bounds): %d", value); + return; + } + charging_current_runtime = value; + ESP_LOGD(TAG, "Runtime charging current updated: %d", charging_current_runtime); +} + +uint16_t evse_get_runtime_charging_current(void) { + return charging_current_runtime; +} + + +// ======================== // Socket outlet +// ======================== bool evse_get_socket_outlet(void) { - ESP_LOGD(TAG, "Socket outlet read: %d", socket_outlet); return socket_outlet; } esp_err_t evse_set_socket_outlet(bool value) { - ESP_LOGD(TAG, "Attempting to set socket outlet: %d", value); - if (value && !board_config.proximity) return ESP_ERR_INVALID_ARG; + if (value && !board_config.proximity) + return ESP_ERR_INVALID_ARG; socket_outlet = value; nvs_set_u8(nvs, "socket_outlet", value); - nvs_commit(nvs); - ESP_LOGD(TAG, "Socket outlet adjusted to: %d", socket_outlet); - return ESP_OK; + return nvs_commit(nvs); } +// ======================== // RCM +// ======================== bool evse_is_rcm(void) { - ESP_LOGD(TAG, "RCM read: %d", rcm); return rcm; } esp_err_t evse_set_rcm(bool value) { - ESP_LOGD(TAG, "Attempting to set RCM: %d", value); - if (value && !board_config.rcm) return ESP_ERR_INVALID_ARG; + if (value && !board_config.rcm) + return ESP_ERR_INVALID_ARG; rcm = value; nvs_set_u8(nvs, "rcm", value); - nvs_commit(nvs); - ESP_LOGD(TAG, "RCM adjusted to: %d", rcm); - return ESP_OK; + return nvs_commit(nvs); } +// ======================== // Temperature +// ======================== uint8_t evse_get_temp_threshold(void) { - ESP_LOGD(TAG, "Temp threshold read: %d", temp_threshold); return temp_threshold; } esp_err_t evse_set_temp_threshold(uint8_t value) { - ESP_LOGI(TAG, "Attempting to set temp threshold: %d", value); - if (value < 40 || value > 80) return ESP_ERR_INVALID_ARG; + if (value < 40 || value > 80) + return ESP_ERR_INVALID_ARG; temp_threshold = value; nvs_set_u8(nvs, "temp_threshold", value); - nvs_commit(nvs); - ESP_LOGI(TAG, "Temp threshold adjusted to: %d", temp_threshold); - return ESP_OK; + return nvs_commit(nvs); } +// ======================== // Authentication +// ======================== bool evse_is_require_auth(void) { - ESP_LOGD(TAG, "Require auth read: %d", require_auth); return require_auth; } void evse_set_require_auth(bool value) { - ESP_LOGI(TAG, "Attempting to set require auth: %d", value); require_auth = value; nvs_set_u8(nvs, "require_auth", value); nvs_commit(nvs); - ESP_LOGD(TAG, "Require auth adjusted to: %d", require_auth); } +// ======================== // Availability +// ======================== static bool is_available = true; bool evse_config_is_available(void) { - ESP_LOGD(TAG, "Checking availability: %d", is_available); return is_available; } void evse_config_set_available(bool available) { - ESP_LOGD(TAG, "Setting availability to: %d", available); is_available = available; } +// ======================== // Enable/Disable +// ======================== static bool is_enabled = true; bool evse_config_is_enabled(void) { - ESP_LOGD(TAG, "Checking if enabled: %d", is_enabled); return is_enabled; } void evse_config_set_enabled(bool enabled) { - ESP_LOGD(TAG, "Setting enabled state to: %d", enabled); is_enabled = enabled; } diff --git a/components/evse/evse_core.c b/components/evse/evse_core.c index 82373d0..44141d5 100755 --- a/components/evse/evse_core.c +++ b/components/evse/evse_core.c @@ -5,7 +5,7 @@ #include "evse_limits.h" #include "evse_config.h" #include "evse_api.h" -#include "pilot.h" +#include "evse_pilot.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "esp_log.h" @@ -15,8 +15,6 @@ static const char *TAG = "evse_core"; static SemaphoreHandle_t mutex; static evse_state_t last_state = EVSE_STATE_A; -static bool authorized = false; -static TickType_t auth_grant_to = 0; static void evse_core_task(void *arg); @@ -41,15 +39,13 @@ void evse_process(void) { pilot_measure(&pilot_voltage, &is_n12v); ESP_LOGD(TAG, "Pilot: %d, -12V: %s", pilot_voltage, is_n12v ? "yes" : "no"); - evse_error_check(pilot_voltage, is_n12v); - if (evse_get_error() == 0 && !evse_is_error_cleared()) { - bool authorized = evse_state_get_authorized(); + evse_error_check(pilot_voltage, is_n12v); evse_fsm_process( pilot_voltage, - authorized, + evse_state_get_authorized(), evse_config_is_available(), evse_config_is_enabled() ); @@ -58,18 +54,19 @@ void evse_process(void) { evse_state_t current = evse_get_state(); if (current != last_state) { - ESP_LOGI(TAG, "State changed: %s → %s", evse_state_to_str(last_state), evse_state_to_str(current)); + ESP_LOGI(TAG, "State changed: %s → %s", + evse_state_to_str(last_state), + evse_state_to_str(current)); last_state = current; } - } - if (evse_get_error() == 0) { evse_mark_error_cleared(); } xSemaphoreGive(mutex); } + // ================================ // Interface pública // ================================ @@ -92,22 +89,6 @@ void evse_set_available(bool value) { evse_config_set_available(value); } -bool evse_is_pending_auth(void) { - return evse_state_is_session(evse_get_state()) && !authorized; -} - -void evse_authorize(void) { - ESP_LOGI(TAG, "Authorize"); - evse_state_set_authorized(true); -} - -void evse_set_authorized(bool value) { - ESP_LOGI(TAG, "Set authorized %d", value); - xSemaphoreTake(mutex, portMAX_DELAY); - authorized = value; - xSemaphoreGive(mutex); -} - // ================================ // Tarefa principal // ================================ diff --git a/components/evse/evse_error.c b/components/evse/evse_error.c index b518c1f..4c45065 100755 --- a/components/evse/evse_error.c +++ b/components/evse/evse_error.c @@ -33,6 +33,7 @@ void evse_error_check(pilot_voltage_t pilot_voltage, bool is_n12v) { if (!(error_bits & EVSE_ERR_DIODE_SHORT_BIT)) { // Verifica se o erro já foi registrado evse_error_set(EVSE_ERR_DIODE_SHORT_BIT); ESP_LOGW(TAG, "Erro: ausência de -12V no PWM (sem diodo)"); + ESP_LOGW(TAG, "Verificando erro: pilot_voltage = %d, is_n12v = %s", pilot_voltage, is_n12v ? "true" : "false"); } } } diff --git a/components/evse/evse_events.c b/components/evse/evse_events.c index e9e1a60..d7ef5fc 100755 --- a/components/evse/evse_events.c +++ b/components/evse/evse_events.c @@ -1,3 +1,3 @@ #include "evse_events.h" -ESP_EVENT_DEFINE_BASE(EVSE_EVENT); +ESP_EVENT_DEFINE_BASE(EVSE_EVENTS); diff --git a/components/evse/evse_fsm.c b/components/evse/evse_fsm.c index bf6af1e..9bf8328 100755 --- a/components/evse/evse_fsm.c +++ b/components/evse/evse_fsm.c @@ -2,7 +2,8 @@ #include "evse_fsm.h" #include "evse_api.h" -#include "pilot.h" +#include "evse_pilot.h" +#include "evse_config.h" #include "esp_log.h" #include "ac_relay.h" #include "board_config.h" @@ -26,7 +27,15 @@ void evse_fsm_reset(void) { c1_d1_relay_to = 0; } -static void update_outputs(evse_state_t state, uint16_t charging_current, uint8_t cable_max_current, bool socket_outlet) { +static void update_outputs(evse_state_t state) { + const uint16_t current = evse_get_runtime_charging_current(); + uint8_t cable_max_current = evse_get_max_charging_current(); + const bool socket_outlet = evse_get_socket_outlet(); + + if (socket_outlet) { + cable_max_current = proximity_get_max_current(); + } + switch (state) { case EVSE_STATE_A: case EVSE_STATE_E: @@ -36,7 +45,6 @@ static void update_outputs(evse_state_t state, uint16_t charging_current, uint8_ if (board_config.socket_lock && socket_outlet) { socket_lock_set_locked(false); } - //energy_meter_stop_session(); break; case EVSE_STATE_B1: @@ -51,16 +59,10 @@ static void update_outputs(evse_state_t state, uint16_t charging_current, uint8_ } else { ESP_LOGW(TAG, "RCM self test failed"); } - - if (socket_outlet) { - cable_max_current = proximity_get_max_current(); - } - - //energy_meter_start_session(); break; case EVSE_STATE_B2: - pilot_set_amps(MIN(charging_current, cable_max_current * 10)); + pilot_set_amps(MIN(current * 10, cable_max_current * 10)); ac_relay_set_state(false); break; @@ -73,7 +75,7 @@ static void update_outputs(evse_state_t state, uint16_t charging_current, uint8_ case EVSE_STATE_C2: case EVSE_STATE_D2: - pilot_set_amps(MIN(charging_current, cable_max_current * 10)); + pilot_set_amps(MIN(current * 10, cable_max_current * 10)); ac_relay_set_state(true); break; } @@ -81,10 +83,10 @@ static void update_outputs(evse_state_t state, uint16_t charging_current, uint8_ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool available, bool enabled) { TickType_t now = xTaskGetTickCount(); - evse_state_t previous_state = evse_get_state(); - evse_state_t current_state = previous_state; + evse_state_t prev = evse_get_state(); + evse_state_t curr = prev; - switch (current_state) { + switch (curr) { case EVSE_STATE_A: if (!available) { evse_set_state(EVSE_STATE_F); @@ -125,15 +127,12 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail break; } } - // fallthrough intencional + __attribute__((fallthrough)); // Evita warning de fallthrough implícito + case EVSE_STATE_C2: case EVSE_STATE_D2: if (!enabled || !available) { - evse_set_state( - (current_state == EVSE_STATE_D2 || current_state == EVSE_STATE_D1) - ? EVSE_STATE_D1 - : EVSE_STATE_C1 - ); + evse_set_state((curr == EVSE_STATE_D2 || curr == EVSE_STATE_D1) ? EVSE_STATE_D1 : EVSE_STATE_C1); break; } @@ -156,8 +155,7 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail break; case EVSE_STATE_E: - // Sem transições a partir de E - break; + break; // Sem transições a partir de E case EVSE_STATE_F: if (available) { @@ -166,9 +164,9 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail break; } - evse_state_t new_state = evse_get_state(); - if (new_state != previous_state) { - ESP_LOGI(TAG, "State changed: %s -> %s", evse_state_to_str(previous_state), evse_state_to_str(new_state)); - update_outputs(new_state, evse_get_charging_current(), evse_get_max_charging_current(), evse_get_socket_outlet()); + evse_state_t next = evse_get_state(); + if (next != prev) { + ESP_LOGI(TAG, "State changed: %s -> %s", evse_state_to_str(prev), evse_state_to_str(next)); + update_outputs(next); } } diff --git a/components/evse/evse_hardware.c b/components/evse/evse_hardware.c index f03e647..5e84b66 100755 --- a/components/evse/evse_hardware.c +++ b/components/evse/evse_hardware.c @@ -1,5 +1,5 @@ #include "evse_hardware.h" -#include "pilot.h" +#include "evse_pilot.h" #include "ac_relay.h" #include "socket_lock.h" #include "proximity.h" @@ -7,6 +7,7 @@ static const char *TAG = "evse_hardware"; void evse_hardware_init(void) { + pilot_init(); pilot_set_level(true); // Sinal piloto em 12V (inicial) ac_relay_set_state(false); // Relé desligado //socket_lock_set_locked(false); // Destrava o conector diff --git a/components/evse/evse_manager.c b/components/evse/evse_manager.c index 5b98241..b19702a 100755 --- a/components/evse/evse_manager.c +++ b/components/evse/evse_manager.c @@ -4,7 +4,6 @@ #include "evse_hardware.h" #include "evse_config.h" #include "evse_api.h" -#include "auth.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -13,12 +12,14 @@ #include "esp_log.h" #include +#include "auth_events.h" +#include "loadbalancer_events.h" +#include "esp_event.h" + static const char *TAG = "EVSE_Manager"; -static TickType_t auth_expiration = 0; - static SemaphoreHandle_t evse_mutex; -static QueueHandle_t auth_event_queue = NULL; +static bool auth_enabled = false; #define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo @@ -30,27 +31,55 @@ static void evse_manager_task(void *arg) { } } -static void evse_auth_event_task(void *arg) { - auth_event_t evt; +// ===== Tratador de eventos de autenticação ===== +static void on_auth_event(void* arg, esp_event_base_t base, int32_t id, void* data) { + if (base != AUTH_EVENTS || data == NULL) return; - while (true) { - if (xQueueReceive(auth_event_queue, &evt, portMAX_DELAY)) { - ESP_LOGI(TAG, "Evento de autenticação recebido: %s (%s)", - evt.tag, evt.authorized ? "AUTORIZADO" : "NEGADO"); + switch (id) { + case AUTH_EVENT_TAG_PROCESSED: { + auth_tag_event_data_t *evt = (auth_tag_event_data_t*)data; + ESP_LOGI("EVSE", "Tag: %s | Autorizada: %s", evt->tag, evt->authorized ? "SIM" : "NÃO"); + evse_state_set_authorized(evt->authorized); + break; + } - if (evt.authorized) { - evse_authorize(); - auth_expiration = xTaskGetTickCount() + pdMS_TO_TICKS(2 * 60 * 1000); // 2 minutos + case AUTH_EVENT_ENABLED_CHANGED: + case AUTH_EVENT_INIT: { + auth_enabled_event_data_t *evt = (auth_enabled_event_data_t*)data; + auth_enabled = evt->enabled; + + ESP_LOGI("EVSE", "Auth %s (%s)", + id == AUTH_EVENT_ENABLED_CHANGED ? "ficou" : "init", + evt->enabled ? "ATIVO" : "INATIVO"); + + if (!auth_enabled) { + evse_state_set_authorized(true); + ESP_LOGI("EVSE", "Autenticação desativada → autorização forçada."); } else { - evse_manager_set_authorized(false); - ESP_LOGW(TAG, "Tag inválida, carregamento negado."); + evse_state_set_authorized(false); + ESP_LOGI("EVSE", "Autenticação ativada → aguardando autorização por tag."); } + break; } } } +// ===== Tratador de eventos de loadbalancer ===== +static void on_loadbalancer_event(void* handler_arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) { + if (event_id == LOADBALANCER_EVENT_INIT || event_id == LOADBALANCER_EVENT_STATE_CHANGED) { + const loadbalancer_state_event_t* evt = (const loadbalancer_state_event_t*) event_data; + ESP_LOGI(TAG, "Loadbalancer %s (ts: %lld)", + evt->enabled ? "ENABLED" : "DISABLED", evt->timestamp_us); + // Ações adicionais podem ser adicionadas aqui conforme necessário + } else if (event_id == LOADBALANCER_EVENT_CHARGING_LIMIT_CHANGED) { + const loadbalancer_charging_limit_event_t* evt = (const loadbalancer_charging_limit_event_t*) event_data; + ESP_LOGD(TAG, "Novo limite de corrente: %.1f A (ts: %lld)", evt->limit, evt->timestamp_us); + evse_set_runtime_charging_current((uint16_t)(evt->limit)); + } +} -// ===== Inicialização dos módulos do EVSE ===== +// ===== Inicialização ===== void evse_manager_init(void) { evse_mutex = xSemaphoreCreateMutex(); @@ -59,17 +88,14 @@ void evse_manager_init(void) { evse_hardware_init(); evse_state_init(); - ESP_LOGI(TAG, "EVSE Manager inicializado."); + ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, ESP_EVENT_ANY_ID, &on_auth_event, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(LOADBALANCER_EVENTS, ESP_EVENT_ANY_ID, &on_loadbalancer_event, NULL)); + ESP_LOGI(TAG, "EVSE Manager inicializado."); xTaskCreate(evse_manager_task, "evse_manager_task", 4096, NULL, 5, NULL); } -// ===== Inicia processamento de eventos de autenticação ===== -void evse_manager_start(QueueHandle_t queue) { - auth_event_queue = queue; - xTaskCreate(evse_auth_event_task, "evse_auth_evt", 4096, NULL, 5, NULL); -} - +// ===== Main Tick ===== void evse_manager_tick(void) { xSemaphoreTake(evse_mutex, portMAX_DELAY); @@ -78,27 +104,25 @@ void evse_manager_tick(void) { evse_state_tick(); evse_temperature_check(); - // Verifica expiração de autorização somente se auth está habilitado - if (auth_is_enabled()) { - if (evse_state_get_authorized() && auth_expiration > 0 && - xTaskGetTickCount() >= auth_expiration) { - ESP_LOGI(TAG, "Autorização expirada após 2 minutos."); + if (auth_enabled) { + // If the car is disconnected, revoke authorization + if (evse_state_get_authorized() && evse_get_state() == EVSE_STATE_A) { + ESP_LOGI(TAG, "Vehicle disconnected → revoking authorization."); evse_state_set_authorized(false); - auth_expiration = 0; } } else { - // Se autenticação não é necessária, sempre considera autorizado + // If authentication is disabled, ensure authorization is always granted if (!evse_state_get_authorized()) { evse_state_set_authorized(true); - ESP_LOGI(TAG, "Autenticação desativada: autorização forçada."); + ESP_LOGI(TAG, "Authentication disabled → forced authorization."); } } - xSemaphoreGive(evse_mutex); } -// ===== Controles e status ===== + +// ===== API pública ===== bool evse_manager_is_available(void) { return evse_config_is_available(); } diff --git a/components/peripherals/src/pilot.c b/components/evse/evse_pilot.c similarity index 76% rename from components/peripherals/src/pilot.c rename to components/evse/evse_pilot.c index 7108bc1..dbf1ff1 100755 --- a/components/peripherals/src/pilot.c +++ b/components/evse/evse_pilot.c @@ -9,7 +9,7 @@ #include "esp_log.h" #include "esp_rom_sys.h" -#include "pilot.h" +#include "evse_pilot.h" #include "adc.h" #include "board_config.h" @@ -21,14 +21,9 @@ #define NUM_PILOT_SAMPLES 100 #define MAX_SAMPLE_ATTEMPTS 1000 -#define PILOT_EXTREME_PERCENT 10 // 15% superior e inferior +#define PILOT_EXTREME_PERCENT 10 // 10% superior e inferior -static const char *TAG = "pilot"; -static pilot_voltage_cache_t last_voltage = {0, 0}; - -static inline uint16_t adc_to_mv(uint16_t x) { - return (uint16_t)(((uint32_t)(x) * 3300U) / 4095U); -} +static const char *TAG = "evse_pilot"; void pilot_init(void) { @@ -92,30 +87,29 @@ void pilot_set_amps(uint16_t amps) ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty); ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL); } - -static int compare_u16(const void *a, const void *b) { - return (*(uint16_t *)a - *(uint16_t *)b); +static int compare_int(const void *a, const void *b) { + return (*(int *)a - *(int *)b); } -static uint16_t select_low_median_qsort(uint16_t *src, int n, int percent) { +static int select_low_median_qsort(int *src, int n, int percent) { int k = (n * percent) / 100; if (k == 0) k = 1; - uint16_t *copy = alloca(n * sizeof(uint16_t)); - memcpy(copy, src, n * sizeof(uint16_t)); + int *copy = alloca(n * sizeof(int)); + memcpy(copy, src, n * sizeof(int)); - qsort(copy, n, sizeof(uint16_t), compare_u16); + qsort(copy, n, sizeof(int), compare_int); return copy[k / 2]; } -static uint16_t select_high_median_qsort(uint16_t *src, int n, int percent) { +static int select_high_median_qsort(int *src, int n, int percent) { int k = (n * percent) / 100; if (k == 0) k = 1; - uint16_t *copy = alloca(n * sizeof(uint16_t)); - memcpy(copy, src, n * sizeof(uint16_t)); + int *copy = alloca(n * sizeof(int)); + memcpy(copy, src, n * sizeof(int)); - qsort(copy, n, sizeof(uint16_t), compare_u16); + qsort(copy, n, sizeof(int), compare_int); return copy[n - k + (k / 2)]; } @@ -123,9 +117,9 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12) { ESP_LOGD(TAG, "pilot_measure"); - uint16_t samples[NUM_PILOT_SAMPLES]; + int samples[NUM_PILOT_SAMPLES]; int collected = 0, attempts = 0; - uint16_t sample; + int sample; while (collected < NUM_PILOT_SAMPLES && attempts < MAX_SAMPLE_ATTEMPTS) { if (adc_oneshot_read(adc_handle, board_config.pilot_adc_channel, &sample) == ESP_OK) { @@ -144,8 +138,11 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12) return; } - uint16_t high_raw = select_high_median_qsort(samples, collected, PILOT_EXTREME_PERCENT); - uint16_t low_raw = select_low_median_qsort(samples, collected, PILOT_EXTREME_PERCENT); + int high_raw = select_high_median_qsort(samples, collected, PILOT_EXTREME_PERCENT); + int low_raw = select_low_median_qsort(samples, collected, PILOT_EXTREME_PERCENT); + + + ESP_LOGD(TAG, "Final: high_raw=%d, low_raw=%d", high_raw, low_raw); int high_mv = 0; int low_mv = 0; @@ -173,14 +170,3 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12) ESP_LOGD(TAG, "Final: up_voltage=%d, down_voltage_n12=%d", *up_voltage, *down_voltage_n12); } - -bool pilot_get_state(void) -{ - pilot_voltage_t voltage; - bool is_n12v; - - pilot_measure(&voltage, &is_n12v); - - // Considera que "estado alto" significa pelo menos 12V (standby ou pronto) - return voltage == PILOT_VOLTAGE_12; -} diff --git a/components/evse/evse_state.c b/components/evse/evse_state.c index 91fdc89..42a511d 100755 --- a/components/evse/evse_state.c +++ b/components/evse/evse_state.c @@ -1,6 +1,8 @@ #include "evse_state.h" +#include "evse_events.h" #include "freertos/FreeRTOS.h" #include "freertos/portmacro.h" +#include "esp_log.h" static evse_state_t current_state = EVSE_STATE_A; static bool is_authorized = false; @@ -8,10 +10,45 @@ static bool is_authorized = false; // Proteção básica para variáveis globais em sistemas concorrentes static portMUX_TYPE state_mux = portMUX_INITIALIZER_UNLOCKED; +static evse_state_event_t map_state_to_event(evse_state_t s) { + switch (s) { + case EVSE_STATE_A: + return EVSE_STATE_EVENT_IDLE; + case EVSE_STATE_B1: + return EVSE_STATE_EVENT_WAITING; + case EVSE_STATE_B2: + case EVSE_STATE_C1: + case EVSE_STATE_C2: + return EVSE_STATE_EVENT_CHARGING; + case EVSE_STATE_E: + case EVSE_STATE_F: + return EVSE_STATE_EVENT_FAULT; + default: + return EVSE_STATE_EVENT_IDLE; + } +} void evse_set_state(evse_state_t state) { + bool changed = false; + evse_state_t previous_state; + portENTER_CRITICAL(&state_mux); - current_state = state; + previous_state = current_state; + if (state != current_state) { + current_state = state; + changed = true; + } portEXIT_CRITICAL(&state_mux); + + if (changed) { + ESP_LOGI("EVSE_STATE", "Estado alterado de %s para %s", + evse_state_to_str(previous_state), + evse_state_to_str(state)); + + evse_state_event_data_t evt = { + .state = map_state_to_event(state) + }; + esp_event_post(EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, &evt, sizeof(evt), portMAX_DELAY); + } } evse_state_t evse_get_state(void) { @@ -39,8 +76,15 @@ const char* evse_state_to_str(evse_state_t state) { void evse_state_init(void) { portENTER_CRITICAL(&state_mux); current_state = EVSE_STATE_A; - is_authorized = false; + is_authorized = true; portEXIT_CRITICAL(&state_mux); + + ESP_LOGI("EVSE_STATE", "Inicializado em estado: %s", evse_state_to_str(current_state)); + + evse_state_event_data_t evt = { + .state = map_state_to_event(current_state) + }; + esp_event_post(EVSE_EVENTS, EVSE_EVENT_INIT, &evt, sizeof(evt), portMAX_DELAY); } void evse_state_tick(void) { diff --git a/components/evse/include/evse_api.h b/components/evse/include/evse_api.h index 80a47cf..9a10e29 100755 --- a/components/evse/include/evse_api.h +++ b/components/evse/include/evse_api.h @@ -23,9 +23,6 @@ bool evse_is_available(void); void evse_set_available(bool value); bool evse_is_require_auth(void); void evse_set_require_auth(bool value); -void evse_authorize(void); -bool evse_is_pending_auth(void); -void evse_set_authorized(bool value); // Corrente uint16_t evse_get_charging_current(void); @@ -35,10 +32,6 @@ esp_err_t evse_set_default_charging_current(uint16_t value); uint8_t evse_get_max_charging_current(void); esp_err_t evse_set_max_charging_current(uint8_t value); -// Grid -uint8_t grid_get_max_current(void); -esp_err_t grid_set_max_current(uint8_t value); - // Temperatura uint8_t evse_get_temp_threshold(void); esp_err_t evse_set_temp_threshold(uint8_t value); diff --git a/components/evse/include/evse_config.h b/components/evse/include/evse_config.h index 22e615d..0d35b59 100755 --- a/components/evse/include/evse_config.h +++ b/components/evse/include/evse_config.h @@ -17,10 +17,6 @@ extern "C" { #define MIN_CHARGING_CURRENT_LIMIT 6 // A #define MAX_CHARGING_CURRENT_LIMIT 32 // A -// Corrente máxima da rede elétrica (grid) -#define MIN_GRID_CURRENT_LIMIT 6 // A -#define MAX_GRID_CURRENT_LIMIT 100 // A - // Corrente via cabo (proximity) — se configurável #define MIN_CABLE_CURRENT_LIMIT 6 // A #define MAX_CABLE_CURRENT_LIMIT 63 // A @@ -43,14 +39,14 @@ esp_err_t evse_set_charging_current(uint16_t value); uint16_t evse_get_default_charging_current(void); esp_err_t evse_set_default_charging_current(uint16_t value); -// Corrente da rede elétrica -uint8_t grid_get_max_current(void); -esp_err_t grid_set_max_current(uint8_t value); - // Configuração de socket outlet bool evse_get_socket_outlet(void); esp_err_t evse_set_socket_outlet(bool socket_outlet); +void evse_set_runtime_charging_current(uint16_t value); +uint16_t evse_get_runtime_charging_current(void); + + // RCM bool evse_is_rcm(void); esp_err_t evse_set_rcm(bool rcm); diff --git a/components/evse/include/evse_error.h b/components/evse/include/evse_error.h index e446e50..1337f8e 100755 --- a/components/evse/include/evse_error.h +++ b/components/evse/include/evse_error.h @@ -3,7 +3,7 @@ #include #include -#include "pilot.h" +#include "evse_pilot.h" #define EVSE_ERR_AUTO_CLEAR_BITS ( \ diff --git a/components/evse/include/evse_events.h b/components/evse/include/evse_events.h index 519718a..114bf0a 100755 --- a/components/evse/include/evse_events.h +++ b/components/evse/include/evse_events.h @@ -1,33 +1,27 @@ #ifndef EVSE_EVENTS_H #define EVSE_EVENTS_H -#include "evse_api.h" -#include "esp_event_base.h" +#pragma once +#include "esp_event.h" -// Certifique-se de que ESP_EVENT_DECLARE_BASE seja corretamente reconhecido -#ifdef __cplusplus -extern "C" { -#endif - -// Declaração da base de eventos EVSE (será definida em evse_events.c) -ESP_EVENT_DECLARE_BASE(EVSE_EVENT); +ESP_EVENT_DECLARE_BASE(EVSE_EVENTS); typedef enum { + EVSE_EVENT_INIT, EVSE_EVENT_STATE_CHANGED, - EVSE_EVENT_ERROR, - EVSE_EVENT_ERROR_CLEARED, - EVSE_EVENT_LIMIT_REACHED, - EVSE_EVENT_AUTH_GRANTED + // Outros eventos possíveis futuramente } evse_event_id_t; -// Estrutura do evento de mudança de estado -typedef struct { - evse_state_t previous; - evse_state_t current; -} evse_event_state_changed_t; +typedef enum { + EVSE_STATE_EVENT_IDLE, + EVSE_STATE_EVENT_WAITING, + EVSE_STATE_EVENT_CHARGING, + EVSE_STATE_EVENT_FAULT +} evse_state_event_t; + +typedef struct { + evse_state_event_t state; +} evse_state_event_data_t; -#ifdef __cplusplus -} -#endif #endif // EVSE_EVENTS_H diff --git a/components/evse/include/evse_fsm.h b/components/evse/include/evse_fsm.h index cb68817..379a240 100755 --- a/components/evse/include/evse_fsm.h +++ b/components/evse/include/evse_fsm.h @@ -4,7 +4,7 @@ #include #include #include "evse_api.h" -#include "pilot.h" +#include "evse_pilot.h" #include "freertos/FreeRTOS.h" #ifdef __cplusplus diff --git a/components/evse/include/evse_manager.h b/components/evse/include/evse_manager.h index 4d0ff54..44433f6 100755 --- a/components/evse/include/evse_manager.h +++ b/components/evse/include/evse_manager.h @@ -1,27 +1,23 @@ #ifndef EVSE_MANAGER_H #define EVSE_MANAGER_H +#pragma once + #ifdef __cplusplus extern "C" { #endif #include +#include #include #include /** * @brief Inicializa os módulos internos do EVSE (hardware, estado, erros, etc.) - * e inicia a tarefa de supervisão periódica (tick). + * e inicia a tarefa de supervisão periódica (tick). */ void evse_manager_init(void); -/** - * @brief Inicia a tarefa que processa eventos de autenticação recebidos via fila. - * - * @param queue Fila de eventos do tipo auth_event_t enviada pelo módulo auth. - */ -void evse_manager_start(QueueHandle_t queue); - /** * @brief Executa uma iteração do ciclo de controle do EVSE. * @@ -66,4 +62,5 @@ bool evse_manager_is_enabled(void); } #endif + #endif // EVSE_MANAGER_H diff --git a/components/peripherals/include/pilot.h b/components/evse/include/evse_pilot.h similarity index 100% rename from components/peripherals/include/pilot.h rename to components/evse/include/evse_pilot.h diff --git a/components/evse/include/evse_state.h b/components/evse/include/evse_state.h index f397654..067c778 100755 --- a/components/evse/include/evse_state.h +++ b/components/evse/include/evse_state.h @@ -1,6 +1,9 @@ #ifndef EVSE_STATE_H #define EVSE_STATE_H +#include "evse_events.h" + + #include // Estado do EVSE (pilot signal) @@ -41,4 +44,6 @@ bool evse_state_is_charging(evse_state_t state); // Retorna true se o estado representa veículo conectado bool evse_state_is_plugged(evse_state_t state); +//evse_state_event_t map_state_to_event(evse_state_t state); + #endif // EVSE_STATE_H diff --git a/components/loadbalancer/CMakeLists.txt b/components/loadbalancer/CMakeLists.txt index 6dc4f64..90de35a 100755 --- a/components/loadbalancer/CMakeLists.txt +++ b/components/loadbalancer/CMakeLists.txt @@ -1,7 +1,8 @@ set(srcs - "src/input_filter.c" "src/loadbalancer.c" + "src/input_filter.c" "src/loadbalancer.c" "src/loadbalancer_events.c" ) idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" - REQUIRES esp_event evse) + PRIV_REQUIRES nvs_flash + REQUIRES esp_event esp_timer meter_manager evse) diff --git a/components/loadbalancer/include/loadbalancer.h b/components/loadbalancer/include/loadbalancer.h index 77562a7..1b5b654 100755 --- a/components/loadbalancer/include/loadbalancer.h +++ b/components/loadbalancer/include/loadbalancer.h @@ -5,13 +5,75 @@ extern "C" { #endif +#include +#include +#include "esp_err.h" + + +/** + * @brief Initializes the load balancer. + * + * This function configures the load balancer and its resources, including + * any necessary persistence configurations, such as storage in NVS (Non-Volatile Storage). + * This function prepares the system to perform load balancing efficiently. + */ void loadbalancer_init(void); + +/** + * @brief Continuous task for the load balancer. + * + * This function executes the load balancing logic continuously, typically in a FreeRTOS task. + * It performs balance calculations, checks the grid current and energy conditions, and adjusts + * the outputs as necessary to ensure efficient energy consumption. + * + * @param param Input parameter, usually used to pass additional information or relevant context + * for the task execution. + */ void loadbalancer_task(void *param); -// Compatibility functions -void setMaxGridCurrent(int max_grid_current); -void setLiveGridCurrent(int live_grid_current); -void setLiveVolt(int live_volt); +/** + * @brief Enables or disables the load balancing system. + * + * This function allows enabling or disabling the load balancing system. When enabled, the load + * balancer starts managing the grid current based on the configured limits. If disabled, the system + * operates without balancing. + * + * The configuration is persisted in NVS, ensuring that the choice is maintained across system restarts. + * + * @param value If true, enables load balancing. If false, disables it. + */ +void loadbalancer_set_enabled(bool value); + +/** + * @brief Checks if load balancing is enabled. + * + * This function returns the current status of the load balancing system. + * + * @return Returns true if load balancing is enabled, otherwise returns false. + */ +bool loadbalancer_is_enabled(void); + +/** + * @brief Sets the maximum grid current. + * + * This function configures the maximum grid current that can be supplied to the load balancing system. + * The value set ensures that the system does not overload the electrical infrastructure and respects + * the safety limits. + * + * @param max_grid_current The maximum allowed current (in amperes) for the load balancing system. + * This value should be appropriate for the grid capacity and the installation. + */ +esp_err_t load_balancing_set_max_grid_current(uint8_t max_grid_current); + + +/** + * @brief Gets the maximum grid current. + * + * This function retrieves the current maximum grid current limit. + * + * @return The maximum grid current (in amperes). + */ +uint8_t load_balancing_get_max_grid_current(void); #ifdef __cplusplus } diff --git a/components/loadbalancer/include/loadbalancer_events.h b/components/loadbalancer/include/loadbalancer_events.h new file mode 100644 index 0000000..7d8de8f --- /dev/null +++ b/components/loadbalancer/include/loadbalancer_events.h @@ -0,0 +1,24 @@ +#pragma once +#include "esp_event.h" +#include +#include +#include "esp_timer.h" + +ESP_EVENT_DECLARE_BASE(LOADBALANCER_EVENTS); + +typedef enum { + LOADBALANCER_EVENT_INIT, + LOADBALANCER_EVENT_STATE_CHANGED, + LOADBALANCER_EVENT_CHARGING_LIMIT_CHANGED +} loadbalancer_event_id_t; + +typedef struct { + float limit; + int64_t timestamp_us; +} loadbalancer_charging_limit_event_t; + +typedef struct { + bool enabled; + int64_t timestamp_us; +} loadbalancer_state_event_t; + diff --git a/components/loadbalancer/src/loadbalancer.c b/components/loadbalancer/src/loadbalancer.c index 6326184..b807df2 100755 --- a/components/loadbalancer/src/loadbalancer.c +++ b/components/loadbalancer/src/loadbalancer.c @@ -1,108 +1,327 @@ #include "loadbalancer.h" -#include "evse_api.h" +#include "loadbalancer_events.h" #include "esp_event.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "input_filter.h" -#include // Para memcpy +#include "nvs_flash.h" +#include "nvs.h" +#include +#include "meter_events.h" +#include "evse_events.h" + + static const char *TAG = "loadbalancer"; +// Limites configuráveis +#define MIN_CHARGING_CURRENT_LIMIT 6 // A +#define MAX_CHARGING_CURRENT_LIMIT 32 // A +#define MIN_GRID_CURRENT_LIMIT 6 // A +#define MAX_GRID_CURRENT_LIMIT 100 // A + +// Parâmetros +static uint8_t max_grid_current = MAX_GRID_CURRENT_LIMIT; +static bool loadbalancer_enabled = false; + static float grid_current = 0.0f; static float evse_current = 0.0f; -static float max_grid_current = 32.0f; // Amperes - -#define MIN_EVSE_CURRENT 6.0f - -// Filtros exponenciais para suavizar leituras static input_filter_t grid_filter; static input_filter_t evse_filter; -static void grid_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) -{ +#define NVS_NAMESPACE "loadbalancing" +#define NVS_MAX_GRID_CURRENT "max_grid_curr" +#define NVS_LOADBALANCER_ENABLED "enabled" - /* - if (id == GRIDMETER_EVENT_UPDATE && data) +static void loadbalancer_meter_event_handler(void *handler_arg, + esp_event_base_t base, + int32_t id, + void *event_data) +{ + if (id != METER_EVENT_DATA_READY || event_data == NULL) + return; + + const meter_event_data_t *evt = (const meter_event_data_t *)event_data; + + ESP_LOGI(TAG, "Received meter event from source: %s", evt->source); + ESP_LOGI(TAG, "Raw IRMS: [%.2f, %.2f, %.2f] A", evt->irms[0], evt->irms[1], evt->irms[2]); + ESP_LOGI(TAG, "Raw VRMS: [%.1f, %.1f, %.1f] V", evt->vrms[0], evt->vrms[1], evt->vrms[2]); + ESP_LOGI(TAG, "Raw Power: [W1=%d, W2=%d, W3=%d]", evt->watt[0], evt->watt[1], evt->watt[2]); + ESP_LOGI(TAG, "Freq: %.2f Hz | PF: %.2f | Energy: %.3f kWh", + evt->frequency, evt->power_factor, evt->total_energy); + + // Calcula a corrente máxima entre as 3 fases + float max_irms = evt->irms[0]; + for (int i = 1; i < 3; ++i) { - float raw; - memcpy(&raw, data, sizeof(float)); - grid_current = input_filter_update(&grid_filter, raw); - ESP_LOGD(TAG, "Grid current (filtered): %.2f A", grid_current); + if (evt->irms[i] > max_irms) + { + max_irms = evt->irms[i]; + } + } + + ESP_LOGI(TAG, "Max IRMS detected: %.2f A", max_irms); + + // Atualiza com filtro exponencial dependendo da origem + if (strncmp(evt->source, "GRID", 4) == 0) + { + grid_current = input_filter_update(&grid_filter, max_irms); + ESP_LOGI(TAG, "GRID IRMS (filtered): %.2f A", grid_current); + } + else if (strncmp(evt->source, "EVSE", 4) == 0) + { + evse_current = input_filter_update(&evse_filter, max_irms); + ESP_LOGI(TAG, "EVSE IRMS (filtered): %.2f A", evse_current); + } + else + { + ESP_LOGW(TAG, "Unknown meter event source: %s", evt->source); } - */ } -static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data) +static void loadbalancer_evse_event_handler(void *handler_arg, + esp_event_base_t base, + int32_t id, + void *event_data) { + const evse_state_event_data_t *evt = (const evse_state_event_data_t *)event_data; - /* - if (id == EVSEMETER_EVENT_UPDATE && data) + ESP_LOGI(TAG, "EVSE state changed: %d", evt->state); + + switch (evt->state) { - float raw; - memcpy(&raw, data, sizeof(float)); - evse_current = input_filter_update(&evse_filter, raw); - ESP_LOGD(TAG, "EVSE current (filtered): %.2f A", evse_current); + case EVSE_STATE_EVENT_IDLE: + // Vehicle is disconnected - current flow can be reduced or reset + ESP_LOGI(TAG, "EVSE is IDLE - possible to release current"); + break; + + case EVSE_STATE_EVENT_WAITING: + // EV is connected but not charging yet (e.g., waiting for authorization) + ESP_LOGI(TAG, "EVSE is waiting - connected but not charging"); + break; + + case EVSE_STATE_EVENT_CHARGING: + grid_current = 0.0f; + evse_current = 0.0f; + // Charging has started - maintain or monitor current usage + ESP_LOGI(TAG, "EVSE is charging"); + break; + + case EVSE_STATE_EVENT_FAULT: + // A fault has occurred - safety measures may be needed + ESP_LOGW(TAG, "EVSE is in FAULT - temporarily disabling load balancing"); + // Optional: disable load balancing during fault condition + // loadbalancer_set_enabled(false); + break; + + default: + ESP_LOGW(TAG, "Unknown EVSE state: %d", evt->state); + break; + } +} + +// Carrega configuração do NVS +static esp_err_t loadbalancer_load_config() +{ + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to open NVS for load/init: %s", esp_err_to_name(err)); + return err; + } + + bool needs_commit = false; + uint8_t temp_u8; + + // max_grid_current + err = nvs_get_u8(handle, NVS_MAX_GRID_CURRENT, &temp_u8); + if (err == ESP_OK && temp_u8 >= MIN_GRID_CURRENT_LIMIT && temp_u8 <= MAX_GRID_CURRENT_LIMIT) + { + max_grid_current = temp_u8; + } + else + { + max_grid_current = MAX_GRID_CURRENT_LIMIT; + nvs_set_u8(handle, NVS_MAX_GRID_CURRENT, max_grid_current); + ESP_LOGW(TAG, "max_grid_current missing or invalid, setting default: %d", max_grid_current); + needs_commit = true; + } + + // loadbalancer_enabled + err = nvs_get_u8(handle, NVS_LOADBALANCER_ENABLED, &temp_u8); + if (err == ESP_OK && temp_u8 <= 1) + { + loadbalancer_enabled = (temp_u8 != 0); + } + else + { + loadbalancer_enabled = false; + nvs_set_u8(handle, NVS_LOADBALANCER_ENABLED, 0); + ESP_LOGW(TAG, "loadbalancer_enabled missing or invalid, setting default: 0"); + needs_commit = true; + } + + if (needs_commit) + { + nvs_commit(handle); + } + + nvs_close(handle); + return ESP_OK; +} + +// Salva o estado habilitado no NVS +void loadbalancer_set_enabled(bool enabled) +{ + ESP_LOGI(TAG, "Setting load balancing enabled to %d", enabled); + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to open NVS: %s", esp_err_to_name(err)); + return; + } + + err = nvs_set_u8(handle, NVS_LOADBALANCER_ENABLED, enabled ? 1 : 0); + if (err == ESP_OK) + { + nvs_commit(handle); + loadbalancer_enabled = enabled; + ESP_LOGI(TAG, "Load balancing enabled state saved"); + + loadbalancer_state_event_t evt = { + .enabled = enabled, + .timestamp_us = esp_timer_get_time()}; + + esp_event_post(LOADBALANCER_EVENTS, + LOADBALANCER_EVENT_STATE_CHANGED, + &evt, + sizeof(evt), + portMAX_DELAY); + } + else + { + ESP_LOGE(TAG, "Failed to save loadbalancer_enabled"); + } + + nvs_close(handle); +} + +// Define e salva o limite de corrente da rede +esp_err_t load_balancing_set_max_grid_current(uint8_t value) +{ + if (value < MIN_GRID_CURRENT_LIMIT || value > MAX_GRID_CURRENT_LIMIT) + { + ESP_LOGE(TAG, "Invalid grid current limit: %d", value); + return ESP_ERR_INVALID_ARG; + } + + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "Failed to open NVS: %s", esp_err_to_name(err)); + return err; + } + + err = nvs_set_u8(handle, NVS_MAX_GRID_CURRENT, value); + if (err == ESP_OK) + { + nvs_commit(handle); + max_grid_current = value; + ESP_LOGI(TAG, "max_grid_current set to: %d", value); + } + else + { + ESP_LOGE(TAG, "Failed to save max_grid_current to NVS"); + } + + nvs_close(handle); + return err; +} + +uint8_t load_balancing_get_max_grid_current(void) +{ + return max_grid_current; +} + +bool loadbalancer_is_enabled(void) +{ + return loadbalancer_enabled; +} + +// Tarefa principal com eventos +void loadbalancer_task(void *param) +{ + while (true) + { + if (!loadbalancer_enabled) + { + vTaskDelay(pdMS_TO_TICKS(1000)); + continue; + } + + float available = max_grid_current - grid_current + evse_current; + + if (available < MIN_CHARGING_CURRENT_LIMIT) + { + available = MIN_CHARGING_CURRENT_LIMIT; + } + else if (available > max_grid_current) + { + available = max_grid_current; + } + + ESP_LOGD(TAG, "Setting EVSE current limit: %.1f A", available); + + loadbalancer_charging_limit_event_t evt = { + .limit = available, + .timestamp_us = esp_timer_get_time()}; + + esp_event_post(LOADBALANCER_EVENTS, + LOADBALANCER_EVENT_CHARGING_LIMIT_CHANGED, + &evt, + sizeof(evt), + portMAX_DELAY); + + vTaskDelay(pdMS_TO_TICKS(1000)); } - */ } void loadbalancer_init(void) { ESP_LOGI(TAG, "Initializing load balancer"); -/* + if (loadbalancer_load_config() != ESP_OK) + { + ESP_LOGW(TAG, "Failed to load/init config. Using in-memory defaults."); + } + input_filter_init(&grid_filter, 0.3f); input_filter_init(&evse_filter, 0.3f); - if (esp_event_handler_register(GRIDMETER_EVENT, GRIDMETER_EVENT_UPDATE, - grid_event_handler, NULL) != ESP_OK) { - ESP_LOGE(TAG, "Failed to register gridmeter event handler"); - } - - if (esp_event_handler_register(EVSEMETER_EVENT, EVSEMETER_EVENT_UPDATE, - evse_event_handler, NULL) != ESP_OK) { - ESP_LOGE(TAG, "Failed to register evsemeter event handler"); - } - - if (xTaskCreate(loadbalancer_task, "loadbalancer", 4096, NULL, 5, NULL) != pdPASS) { + if (xTaskCreate(loadbalancer_task, "loadbalancer", 4096, NULL, 4, NULL) != pdPASS) + { ESP_LOGE(TAG, "Failed to create loadbalancer task"); } -*/ -} - -void loadbalancer_task(void *param) -{ - while (true) - { - float available = max_grid_current - grid_current + evse_current; - - // Restrição de corrente mínima e máxima - if (available < MIN_EVSE_CURRENT) { - available = 0.0f; - } else if (available > max_grid_current) { - available = max_grid_current; - } - - ESP_LOGI(TAG, "Setting EVSE current limit: %.1f A", available); - evse_set_charging_current((uint16_t)available); - - vTaskDelay(pdMS_TO_TICKS(1000)); - } -} - -void setMaxGridCurrent(int value) -{ - max_grid_current = value / 10.0f; -} - -void setLiveGridCurrent(int value) -{ - float raw = value / 10.0f; - grid_current = input_filter_update(&grid_filter, raw); -} - -void setLiveVolt(int value) -{ - (void)value; // reservado para uso futuro + + loadbalancer_state_event_t evt = { + .enabled = loadbalancer_enabled, + .timestamp_us = esp_timer_get_time()}; + + esp_event_post(LOADBALANCER_EVENTS, + LOADBALANCER_EVENT_INIT, + &evt, + sizeof(evt), + portMAX_DELAY); + + ESP_ERROR_CHECK(esp_event_handler_register(METER_EVENT, METER_EVENT_DATA_READY, + &loadbalancer_meter_event_handler, NULL)); + + ESP_ERROR_CHECK(esp_event_handler_register(EVSE_EVENTS, + EVSE_EVENT_STATE_CHANGED, + &loadbalancer_evse_event_handler, + NULL)); } diff --git a/components/loadbalancer/src/loadbalancer_events.c b/components/loadbalancer/src/loadbalancer_events.c new file mode 100644 index 0000000..abcf061 --- /dev/null +++ b/components/loadbalancer/src/loadbalancer_events.c @@ -0,0 +1,4 @@ +#include "loadbalancer_events.h" + +// Define a base de eventos para o loadbalancer +ESP_EVENT_DEFINE_BASE(LOADBALANCER_EVENTS); diff --git a/components/meter_manager/CMakeLists.txt b/components/meter_manager/CMakeLists.txt index db4f00a..63d9418 100755 --- a/components/meter_manager/CMakeLists.txt +++ b/components/meter_manager/CMakeLists.txt @@ -1,11 +1,13 @@ # List the source files to be compiled set(srcs "driver/meter_ade7758/meter_ade7758.c" + "driver/meter_ade7758/ade7758.c" "driver/meter_orno/meter_orno513.c" "driver/meter_orno/meter_orno516.c" "driver/meter_orno/modbus_params.c" "driver/meter_zigbee/meter_zigbee.c" "src/meter_manager.c" + "src/meter_events.c" ) # List the include directories @@ -19,4 +21,5 @@ set(includes # Register the component with the ESP-IDF build system idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${includes}" + PRIV_REQUIRES nvs_flash REQUIRES esp_event esp-modbus) diff --git a/components/meter_manager/driver/meter_ade7758/meter_ade7758.c b/components/meter_manager/driver/meter_ade7758/meter_ade7758.c index 1b15364..1882d46 100755 --- a/components/meter_manager/driver/meter_ade7758/meter_ade7758.c +++ b/components/meter_manager/driver/meter_ade7758/meter_ade7758.c @@ -1,5 +1,6 @@ #include "meter_ade7758.h" #include "ade7758.h" +#include "meter_events.h" #include #include @@ -42,22 +43,23 @@ static SemaphoreHandle_t meter_mutex = NULL; static uint32_t meter_watchdog_counter = 0; // === Utilitários internos === +static void meter_ade7758_post_event(const meter_ade7758_internal_data_t *data) { + meter_event_data_t evt = { + .frequency = 0, + .power_factor = 0, + .total_energy = 0 + }; -static void meter_ade7758_clear_internal_data(void) { - if (meter_mutex && xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - memset(&meter_data, 0, sizeof(meter_data)); - xSemaphoreGive(meter_mutex); - } -} + memcpy(evt.vrms, data->vrms, sizeof(evt.vrms)); + memcpy(evt.irms, data->irms, sizeof(evt.irms)); + memcpy(evt.watt, data->watt, sizeof(evt.watt)); -static bool meter_ade7758_read_internal(meter_ade7758_internal_data_t *out) { - if (!out) return false; - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - *out = meter_data; - xSemaphoreGive(meter_mutex); - return true; + esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, + &evt, sizeof(evt), pdMS_TO_TICKS(10)); + + if (err != ESP_OK) { + ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err)); } - return false; } static void meter_ade7758_task_func(void *param) { @@ -66,27 +68,29 @@ static void meter_ade7758_task_func(void *param) { meter_ade7758_internal_data_t previous = {0}; while (true) { - meter_ade7758_internal_data_t current = {0}; + meter_ade7758_internal_data_t meterData = {0}; - current.vrms[0] = avrms() / VRMS_CAL; - current.vrms[1] = bvrms() / VRMS_CAL; - current.vrms[2] = cvrms() / VRMS_CAL; + meterData.vrms[0] = avrms() / VRMS_CAL; + meterData.vrms[1] = bvrms() / VRMS_CAL; + meterData.vrms[2] = cvrms() / VRMS_CAL; - current.irms[0] = airms() / IRMS_CAL; - current.irms[1] = birms() / IRMS_CAL; - current.irms[2] = cirms() / IRMS_CAL; + meterData.irms[0] = airms() / IRMS_CAL; + meterData.irms[1] = birms() / IRMS_CAL; + meterData.irms[2] = cirms() / IRMS_CAL; - if (setPotLine(PHASE_A, 20)) current.watt[0] = getWatt(PHASE_A); - if (setPotLine(PHASE_B, 20)) current.watt[1] = getWatt(PHASE_B); - if (setPotLine(PHASE_C, 20)) current.watt[2] = getWatt(PHASE_C); + if (setPotLine(PHASE_A, 20)) meterData.watt[0] = getWatt(PHASE_A); + if (setPotLine(PHASE_B, 20)) meterData.watt[1] = getWatt(PHASE_B); + if (setPotLine(PHASE_C, 20)) meterData.watt[2] = getWatt(PHASE_C); - if (memcmp(&previous, ¤t, sizeof(current)) != 0) { + if (memcmp(&previous, &meterData, sizeof(meterData)) != 0) { if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - meter_data = current; + meter_data = meterData; meter_watchdog_counter++; xSemaphoreGive(meter_mutex); + + meter_ade7758_post_event(&meterData); } - previous = current; + previous = meterData; } vTaskDelay(pdMS_TO_TICKS(METER_READ_INTERVAL_MS)); @@ -106,8 +110,6 @@ esp_err_t meter_ade7758_init(void) { } } - meter_ade7758_clear_internal_data(); - esp_err_t err = Init(EEPROM_HOST, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK); if (err != ESP_OK) { ESP_LOGE(TAG, "Erro ao inicializar SPI (%d)", err); @@ -126,8 +128,7 @@ esp_err_t meter_ade7758_init(void) { esp_err_t meter_ade7758_start(void) { if (meter_task) return ESP_ERR_INVALID_STATE; - meter_ade7758_clear_internal_data(); - BaseType_t result = xTaskCreate(meter_ade7758_task_func, "meter_ade7758_task", 4096, NULL, 5, &meter_task); + BaseType_t result = xTaskCreate(meter_ade7758_task_func, "meter_ade7758_task", 4096, NULL, 3, &meter_task); return result == pdPASS ? ESP_OK : ESP_FAIL; } @@ -136,41 +137,4 @@ void meter_ade7758_stop(void) { vTaskDelete(meter_task); meter_task = NULL; } - meter_ade7758_clear_internal_data(); -} - -bool meter_ade7758_is_running(void) { - return meter_task != NULL; -} - -void meter_ade7758_clear_data(void) { - meter_ade7758_clear_internal_data(); -} - -// === Interface pública: acesso aos dados === - -float meter_ade7758_get_vrms_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[0] : 0; } -float meter_ade7758_get_vrms_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[1] : 0; } -float meter_ade7758_get_vrms_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.vrms[2] : 0; } - -float meter_ade7758_get_irms_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[0] : 0; } -float meter_ade7758_get_irms_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[1] : 0; } -float meter_ade7758_get_irms_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.irms[2] : 0; } - -int meter_ade7758_get_watt_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[0] : 0; } -int meter_ade7758_get_watt_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[1] : 0; } -int meter_ade7758_get_watt_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.watt[2] : 0; } - -int meter_ade7758_get_var_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[0] : 0; } -int meter_ade7758_get_var_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[1] : 0; } -int meter_ade7758_get_var_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.var[2] : 0; } - -int meter_ade7758_get_va_l1(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[0] : 0; } -int meter_ade7758_get_va_l2(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[1] : 0; } -int meter_ade7758_get_va_l3(void) { meter_ade7758_internal_data_t d; return meter_ade7758_read_internal(&d) ? d.va[2] : 0; } - -// === Diagnóstico === - -uint32_t meter_ade7758_get_watchdog_counter(void) { - return meter_watchdog_counter; } diff --git a/components/meter_manager/driver/meter_ade7758/meter_ade7758.h b/components/meter_manager/driver/meter_ade7758/meter_ade7758.h index 9c1c5bc..c7bf182 100755 --- a/components/meter_manager/driver/meter_ade7758/meter_ade7758.h +++ b/components/meter_manager/driver/meter_ade7758/meter_ade7758.h @@ -23,47 +23,6 @@ esp_err_t meter_ade7758_start(void); */ void meter_ade7758_stop(void); -/** - * @brief Verifica se o medidor ADE7758 está em execução. - * - * @return true se a tarefa estiver ativa, false caso contrário. - */ -bool meter_ade7758_is_running(void); - -/** - * @brief Limpa os dados armazenados no medidor ADE7758 (zera todos os valores). - */ -void meter_ade7758_clear_data(void); - -// ----- Leituras por fase (L1, L2, L3) ----- - -// Tensão RMS (em volts) -float meter_ade7758_get_vrms_l1(void); -float meter_ade7758_get_vrms_l2(void); -float meter_ade7758_get_vrms_l3(void); - -// Corrente RMS (em amperes) -float meter_ade7758_get_irms_l1(void); -float meter_ade7758_get_irms_l2(void); -float meter_ade7758_get_irms_l3(void); - -// Potência ativa (W) -int meter_ade7758_get_watt_l1(void); -int meter_ade7758_get_watt_l2(void); -int meter_ade7758_get_watt_l3(void); - -// Potência reativa (VAR) -int meter_ade7758_get_var_l1(void); -int meter_ade7758_get_var_l2(void); -int meter_ade7758_get_var_l3(void); - -// Potência aparente (VA) -int meter_ade7758_get_va_l1(void); -int meter_ade7758_get_va_l2(void); -int meter_ade7758_get_va_l3(void); - -// (Opcional) contador de watchdog para diagnóstico -uint32_t meter_ade7758_get_watchdog_counter(void); #ifdef __cplusplus } diff --git a/components/meter_manager/driver/meter_orno/meter_orno513.c b/components/meter_manager/driver/meter_orno/meter_orno513.c index f59f058..1c03fc3 100755 --- a/components/meter_manager/driver/meter_orno/meter_orno513.c +++ b/components/meter_manager/driver/meter_orno/meter_orno513.c @@ -1,325 +1,206 @@ -#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE -#include "esp_log.h" - #include "meter_orno513.h" -#include "modbus_params.h" // for modbus parameters structures +#include "modbus_params.h" #include "mbcontroller.h" -#include "sdkconfig.h" +#include "meter_events.h" +#include "esp_log.h" +#include "driver/uart.h" +#include -#define TXD_PIN (GPIO_NUM_17) -#define RXD_PIN (GPIO_NUM_16) +#define TAG "serial_mdb_orno513" -static const char *TAG = "serial_mdb"; +#define MB_PORT_NUM 2 +#define MB_DEV_SPEED 9600 +#define MB_UART_TXD 17 +#define MB_UART_RXD 16 +#define MB_UART_RTS 5 +#define UPDATE_INTERVAL (3000 / portTICK_PERIOD_MS) +#define POLL_INTERVAL (100 / portTICK_PERIOD_MS) -static bool enabled = false; -static bool meterState = false; -static bool meterTest = false; - -static TaskHandle_t serial_mdb_task = NULL; - -#define MB_PORT_NUM 2 //(CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection -#define MB_DEV_SPEED 9600 //(CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART - -#define MB_UART_TXD 17 -#define MB_UART_RXD 16 -#define MB_UART_RTS 5 - -// The number of parameters that intended to be used in the particular control process -#define MASTER_MAX_CIDS num_device_parameters - -// Number of reading of parameters from slave -#define MASTER_MAX_RETRY 30 - -// Timeout to update cid over Modbus -#define UPDATE_CIDS_TIMEOUT_MS (3000) -#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS) - -// Timeout between polls -#define POLL_TIMEOUT_MS (500) -#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_PERIOD_MS) - -// Timeout between errors -#define ERROR_TIMEOUT_MS (1000) -#define ERROR_TIMEOUT_TICS (ERROR_TIMEOUT_MS / portTICK_PERIOD_MS) - -// The macro to get offset for parameter in the appropriate structure #define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1)) -#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1)) -#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1)) -// Discrete offset macro -#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1)) +#define STR(x) ((const char *)(x)) +#define OPTS(min, max, step) {.opt1 = min, .opt2 = max, .opt3 = step} -#define STR(fieldname) ((const char *)(fieldname)) -// Options can be used as bit masks or parameter limits -#define OPTS(min_val, max_val, step_val) \ - { \ - .opt1 = min_val, .opt2 = max_val, .opt3 = step_val} +// State flag +static bool is_initialized = false; +static TaskHandle_t meter_task = NULL; -// Enumeration of modbus device addresses accessed by master device -enum -{ - MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here) +// CID enums +enum { + CID_TOTAL_ACTIVE_ENERGY = 0, + CID_TOTAL_REACTIVE_ENERGY, + CID_ACTIVE_POWER, + CID_APPARENT_POWER, + CID_REACTIVE_POWER, + CID_L1_CURRENT, + CID_L1_VOLTAGE }; -// Enumeration of all supported CIDs for device (used in parameter definition table) -enum -{ - CID_HOLD_DATA_0 = 0, - CID_HOLD_DATA_1 = 1, - CID_HOLD_DATA_2 = 2, - CID_HOLD_DATA_3 = 3, - CID_HOLD_DATA_4 = 4, - CID_HOLD_DATA_5 = 5, - CID_HOLD_DATA_6 = 6 +// Register addresses +#define TOTALFACTIVE 0x010E +#define TOTALRACTIVE 0x0118 +#define ACTIVEPOWER 0x0104 +#define APPARENTPOWER 0x0106 +#define REACTIVEPOWER 0x0108 +#define L1CURRENT 0x0102 +#define L1VOLTAGE 0x0100 + +const mb_parameter_descriptor_t device_parameters_orno513[] = { + {CID_TOTAL_ACTIVE_ENERGY, STR("Total Active Energy"), STR("kWh"), 1, MB_PARAM_HOLDING, TOTALFACTIVE, 2, + HOLD_OFFSET(total_active_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + + {CID_TOTAL_REACTIVE_ENERGY, STR("Total Reactive Energy"), STR("kWh"), 1, MB_PARAM_HOLDING, TOTALRACTIVE, 2, + HOLD_OFFSET(total_reactive_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + + {CID_ACTIVE_POWER, STR("Active Power"), STR("W"), 1, MB_PARAM_HOLDING, ACTIVEPOWER, 2, + HOLD_OFFSET(active_power), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, + + {CID_APPARENT_POWER, STR("Apparent Power"), STR("VA"), 1, MB_PARAM_HOLDING, APPARENTPOWER, 2, + HOLD_OFFSET(apparent_power), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100000, 1), PAR_PERMS_READ}, + + {CID_REACTIVE_POWER, STR("Reactive Power"), STR("VAR"), 1, MB_PARAM_HOLDING, REACTIVEPOWER, 2, + HOLD_OFFSET(reactive_power), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, + + {CID_L1_CURRENT, STR("L1 Current"), STR("A"), 1, MB_PARAM_HOLDING, L1CURRENT, 2, + HOLD_OFFSET(l1_current), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 100, 0.1), PAR_PERMS_READ}, + + {CID_L1_VOLTAGE, STR("L1 Voltage"), STR("V"), 1, MB_PARAM_HOLDING, L1VOLTAGE, 2, + HOLD_OFFSET(l1_voltage), PARAM_TYPE_I32_CDAB, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ} }; -#define SN 0x1000 -#define METERID 0x1003 -#define FW 0x1004 +const uint16_t num_device_parameters_orno513 = sizeof(device_parameters_orno513) / sizeof(device_parameters_orno513[0]); -#define L1VOLTAGE 0x0100 -#define L1CURRENT 0x0102 -#define ACTIVEPOWER 0x0104 -#define APPARENTPOWER 0x0106 -#define REACTIVEPOWER 0x0108 - -#define TOTALFACTIVE 0x010E -#define TOTALRACTIVE 0x0118 - -// Example Data (Object) Dictionary for Modbus parameters: -const mb_parameter_descriptor_t device_parameters[] = { - {CID_HOLD_DATA_0, STR("TOTALFACTIVE"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALFACTIVE, 2, - HOLD_OFFSET(holding_data0), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_1, STR("TOTALRACTIVE"), STR("kWh"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, TOTALRACTIVE, 2, - HOLD_OFFSET(holding_data1), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_2, STR("ACTIVEPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, ACTIVEPOWER, 2, - HOLD_OFFSET(holding_data2), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_3, STR("APPARENTPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, APPARENTPOWER, 2, - HOLD_OFFSET(holding_data3), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_4, STR("REACTIVEPOWER"), STR("W"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, REACTIVEPOWER, 2, - HOLD_OFFSET(holding_data4), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_5, STR("L1CURRENT"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2, - HOLD_OFFSET(holding_data5), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_6, STR("L1VOLTAGE"), STR("V"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1VOLTAGE, 2, - HOLD_OFFSET(holding_data6), PARAM_TYPE_I32_CDAB, 4, OPTS(-100000, 100000, 1), PAR_PERMS_READ} -}; - -// Calculate number of parameters in the table -const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0])); - -// Function to get pointer to parameter storage (instance) according to parameter description table -static void *master_get_param_data(const mb_parameter_descriptor_t *param_descriptor) -{ - assert(param_descriptor != NULL); - void *instance_ptr = NULL; - if (param_descriptor->param_offset != 0) - { - switch (param_descriptor->mb_param_type) - { - case MB_PARAM_HOLDING: - instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1); - break; - case MB_PARAM_INPUT: - instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1); - break; - case MB_PARAM_COIL: - instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1); - break; - case MB_PARAM_DISCRETE: - instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1); - break; - default: - instance_ptr = NULL; - break; - } - } - else - { - ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid); - assert(instance_ptr != NULL); - } - return instance_ptr; +static void *get_param_ptr(const mb_parameter_descriptor_t *param) { + if (!param || param->param_offset == 0) return NULL; + return ((uint8_t *)&holding_reg_params + param->param_offset - 1); } -// Float - Mid-Little Endian (CDAB) -float ReverseFloat(const float inFloat) -{ - float retVal; - char *floatToConvert = (char *)&inFloat; - char *returnFloat = (char *)&retVal; +static void serial_mdb_task(void *param) { + esp_err_t err; + const mb_parameter_descriptor_t *desc = NULL; - // swap the bytes into a temporary buffer - returnFloat[0] = floatToConvert[2]; - returnFloat[1] = floatToConvert[3]; - returnFloat[2] = floatToConvert[0]; - returnFloat[3] = floatToConvert[1]; + float voltage[3] = {0}; + float current[3] = {0}; + int watt[3] = {0}; + float energy = 0.0f; - return retVal; -} + while (1) { + for (uint16_t cid = 0; cid < num_device_parameters_orno513; cid++) { + err = mbc_master_get_cid_info(cid, &desc); + if (err != ESP_OK || !desc) continue; -static void serial_mdb_task_func(void *param) -{ - ESP_LOGI(TAG, "serial_mdb_task_func"); - esp_err_t err = ESP_OK; + void *data_ptr = get_param_ptr(desc); + uint8_t type = 0; + err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data_ptr, &type); - float l1current = 0; - int error_count = 0; + if (err == ESP_OK && data_ptr) { + int32_t raw = *(int32_t *)data_ptr; + float val = raw / 10.0f; + ESP_LOGI(TAG, "%s: %.2f %s", desc->param_key, val, desc->param_units); - bool alarm_state = false; - const mb_parameter_descriptor_t *param_descriptor = NULL; - - ESP_LOGI(TAG, "Start modbus..."); - - while (true) - { - // Read all found characteristics from slave(s) - for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) - { - // Get data from parameters description table - err = mbc_master_get_cid_info(cid, ¶m_descriptor); - if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) - { - void *temp_data_ptr = master_get_param_data(param_descriptor); - uint8_t type = 0; - - err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key, - (uint8_t *)temp_data_ptr, &type); - - if (err == ESP_OK) - { - error_count = 0; - meterState = true; - - if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) || - (param_descriptor->mb_param_type == MB_PARAM_INPUT)) - { - int value = *(int *)temp_data_ptr; - - ESP_LOGI(TAG, "Characteristic #%u %s (%s) value = %d (0x%" PRIx32 ") read successful.", - param_descriptor->cid, - param_descriptor->param_key, - param_descriptor->param_units, - value, - *(uint32_t *)temp_data_ptr); - - if (((value > param_descriptor->param_opts.max) || - (value < param_descriptor->param_opts.min))) - { - alarm_state = true; - break; - } - } + switch (cid) { + case CID_L1_VOLTAGE: voltage[0] = val; break; + case CID_L1_CURRENT: current[0] = val; break; + case CID_ACTIVE_POWER: + watt[0] = (int)(val); + watt[1] = watt[0]; + watt[2] = watt[0]; + break; + case CID_TOTAL_ACTIVE_ENERGY: + energy = val / 1000.0f; + break; + default: + break; } - else - { - if (error_count > 3 && !meterTest) - { - meterState = false; - vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls - } - else - { - error_count++; - } - - ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).", - param_descriptor->cid, - param_descriptor->param_key, - (int)err, - (char *)esp_err_to_name(err)); - } - - vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls + } else { + ESP_LOGE(TAG, "CID %u (%s) read failed: %s", cid, desc->param_key, esp_err_to_name(err)); } + + vTaskDelay(POLL_INTERVAL); } - vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS); - } + meter_event_data_t evt = { + .frequency = 0.0f, + .power_factor = 0.0f, + .total_energy = energy, + .source = "GRID" + }; - if (alarm_state) - { - ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid); + memcpy(evt.vrms, voltage, sizeof(evt.vrms)); + memcpy(evt.irms, current, sizeof(evt.irms)); + memcpy(evt.watt, watt, sizeof(evt.watt)); + + esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, &evt, sizeof(evt), pdMS_TO_TICKS(10)); + + + vTaskDelay(UPDATE_INTERVAL); } - else - { - ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY); - } - ESP_LOGI(TAG, "Destroy master..."); - ESP_ERROR_CHECK(mbc_master_destroy()); } -// Modbus master initialization -static esp_err_t master_init(void) -{ +esp_err_t meter_orno513_init(void) { + if (is_initialized) { + ESP_LOGW(TAG, "meter_orno513 already initialized"); + return ESP_ERR_INVALID_STATE; + } + + ESP_LOGI(TAG, "meter_orno513_init"); + mb_communication_info_t comm = { .port = MB_PORT_NUM, .mode = MB_MODE_RTU, .baudrate = MB_DEV_SPEED, - .parity = UART_PARITY_DISABLE}; - void *master_handler = NULL; + .parity = UART_PARITY_DISABLE + }; - esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler); - ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG, - "mb controller initialization fail."); - ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller initialization fail, returns(0x%x).", (int)err); - err = mbc_master_setup((void *)&comm); - ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller setup fail, returns(0x%x).", (int)err); + void *handler = NULL; - err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, - MB_UART_RTS, UART_PIN_NO_CHANGE); - ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err); - - err = mbc_master_start(); - ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller start fail, returned (0x%x).", (int)err); - - err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX); - ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err); - - vTaskDelay(5); - err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters); - ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller set descriptor fail, returns(0x%x).", (int)err); - ESP_LOGI(TAG, "Modbus master stack initialized..."); - return err; -} - - -// Function to start the meter -esp_err_t meter_orno513_start(void) -{ - ESP_LOGI(TAG, "Starting MDB Serial"); - - // Call the initialization function directly - esp_err_t err = master_init(); // Don't wrap this in ESP_ERROR_CHECK - ESP_ERROR_CHECK(err); // Check if there was an error during initialization - - // Create the task for reading Modbus data - xTaskCreate(serial_mdb_task_func, "serial_mdb_task", 4 * 1024, NULL, 5, &serial_mdb_task); - - return err; -} - -// Function to stop the meter -void meter_orno513_stop(void) -{ - ESP_LOGI(TAG, "Stopping"); - - if (serial_mdb_task) - { - vTaskDelete(serial_mdb_task); - serial_mdb_task = NULL; + esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &handler); + if (err != ESP_OK) { + ESP_LOGE(TAG, "mbc_master_init failed"); + return err; } - uart_driver_delete(MB_PORT_NUM); + ESP_ERROR_CHECK(mbc_master_setup(&comm)); + ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, MB_UART_RTS, UART_PIN_NO_CHANGE)); + ESP_ERROR_CHECK(mbc_master_start()); + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + vTaskDelay(pdMS_TO_TICKS(5)); + ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters_orno513, num_device_parameters_orno513)); + + is_initialized = true; + return ESP_OK; +} + +esp_err_t meter_orno513_start(void) { + + ESP_LOGI(TAG, "meter_orno513_start"); + + if (!is_initialized) { + ESP_LOGE(TAG, "meter_orno513 not initialized"); + return ESP_ERR_INVALID_STATE; + } + + if (meter_task == NULL) { + xTaskCreate(serial_mdb_task, "meter_orno513_task", 4096, NULL, 3, &meter_task); + ESP_LOGI(TAG, "meter_orno513 task started"); + } + + return ESP_OK; +} + +void meter_orno513_stop(void) { + if (!is_initialized) { + ESP_LOGW(TAG, "meter_orno513 not initialized"); + return; + } + + ESP_LOGI(TAG, "Stopping meter_orno513"); + + uart_driver_delete(MB_PORT_NUM); + + esp_err_t err = mbc_master_destroy(); + if (err != ESP_OK) { + ESP_LOGW(TAG, "mbc_master_destroy() returned %s", esp_err_to_name(err)); + } + + is_initialized = false; } diff --git a/components/meter_manager/driver/meter_orno/meter_orno513.h b/components/meter_manager/driver/meter_orno/meter_orno513.h index 734208c..2be2596 100755 --- a/components/meter_manager/driver/meter_orno/meter_orno513.h +++ b/components/meter_manager/driver/meter_orno/meter_orno513.h @@ -23,37 +23,6 @@ esp_err_t meter_orno513_start(void); */ void meter_orno513_stop(void); -/** - * @brief Verifica se o medidor ORNO 513 está em execução. - * - * @return true se a tarefa estiver ativa, false caso contrário. - */ -bool meter_orno513_is_running(void); - -/** - * @brief Limpa os dados armazenados no medidor ORNO 513 (zera todos os valores). - */ -void meter_orno513_clear_data(void); - -// ----- Leituras por fase (L1) ----- - -// Tensão RMS (em volts) -float meter_orno513_get_vrms_l1(void); - -// Corrente RMS (em amperes) -float meter_orno513_get_irms_l1(void); - -// Potência ativa (W) -int meter_orno513_get_watt_l1(void); - -// Potência reativa (VAR) -int meter_orno513_get_var_l1(void); - -// Potência aparente (VA) -int meter_orno513_get_va_l1(void); - -// (Opcional) contador de watchdog para diagnóstico -uint32_t meter_orno513_get_watchdog_counter(void); #ifdef __cplusplus } diff --git a/components/meter_manager/driver/meter_orno/meter_orno516.c b/components/meter_manager/driver/meter_orno/meter_orno516.c index 449cc68..56f7141 100755 --- a/components/meter_manager/driver/meter_orno/meter_orno516.c +++ b/components/meter_manager/driver/meter_orno/meter_orno516.c @@ -1,383 +1,217 @@ -#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE -#include "esp_log.h" - #include "meter_orno516.h" -#include "modbus_params.h" // for modbus parameters structures +#include "meter_events.h" +#include "modbus_params.h" #include "mbcontroller.h" -#include "sdkconfig.h" +#include "esp_log.h" +#include "driver/uart.h" +#include -#define TXD_PIN (GPIO_NUM_17) -#define RXD_PIN (GPIO_NUM_16) - -static const char *TAG = "serial_mdb_orno516"; - -static bool enabled = false; -static bool meterState = false; -static bool meterTest = false; - -static TaskHandle_t serial_mdb_task = NULL; - -#define MB_PORT_NUM 2 //(CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection -#define MB_DEV_SPEED 9600 //(CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART -// #define MB_PARITY_EVEN +#define TAG "serial_mdb_orno516" +#define MB_PORT_NUM 2 +#define MB_DEV_SPEED 9600 #define MB_UART_TXD 17 #define MB_UART_RXD 16 #define MB_UART_RTS 5 -// Note: Some pins on target chip cannot be assigned for UART communication. -// See UART documentation for selected board and target to configure pins using Kconfig. +#define UPDATE_INTERVAL (5000 / portTICK_PERIOD_MS) +#define POLL_INTERVAL (100 / portTICK_PERIOD_MS) -// The number of parameters that intended to be used in the particular control process -#define MASTER_MAX_CIDS num_device_parameters_orno516 - -// Number of reading of parameters from slave -#define MASTER_MAX_RETRY 30 - -// Timeout to update cid over Modbus -#define UPDATE_CIDS_TIMEOUT_MS (5000) -#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_PERIOD_MS) - -// Timeout between polls -#define POLL_TIMEOUT_MS (1) -#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_PERIOD_MS) - -// Timeout between erros -#define ERROR_TIMEOUT_MS (30000) -#define ERROR_TIMEOUT_TICS (ERROR_TIMEOUT_MS / portTICK_PERIOD_MS) - -// The macro to get offset for parameter in the appropriate structure #define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1)) -#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1)) -#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1)) -// Discrete offset macro -#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1)) - #define STR(fieldname) ((const char *)(fieldname)) -// Options can be used as bit masks or parameter limits -#define OPTS(min_val, max_val, step_val) \ - { \ - .opt1 = min_val, .opt2 = max_val, .opt3 = step_val} +#define OPTS(min_val, max_val, step_val) {.opt1 = min_val, .opt2 = max_val, .opt3 = step_val} -// Enumeration of modbus device addresses accessed by master device -enum -{ - MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here) +// Estado do driver +static bool is_initialized = false; +static TaskHandle_t meter_task = NULL; + +#define L1VOLTAGE 0x000E +#define L2VOLTAGE 0x0010 +#define L3VOLTAGE 0x0012 +#define L1CURRENT 0x0016 +#define L2CURRENT 0x0018 +#define L3CURRENT 0x001A +#define TOTALACTIVEPOWER 0x001C + +enum { + CID_L1_CURRENT = 0, + CID_L2_CURRENT, + CID_L3_CURRENT, + CID_L1_VOLTAGE, + CID_L2_VOLTAGE, + CID_L3_VOLTAGE, + CID_TOTAL_ACTIVE_POWER }; -// Enumeration of all supported CIDs for device (used in parameter definition table) -enum -{ - CID_HOLD_DATA_0 = 0, - CID_HOLD_DATA_1 = 1, - CID_HOLD_DATA_2 = 2, - CID_HOLD_DATA_3 = 3, - CID_HOLD_DATA_4 = 4, - CID_HOLD_DATA_5 = 5, - CID_HOLD_DATA_6 = 6 -}; - -#define SN 0x01 -#define METERID 0x02 - -#define L1VOLTAGE 0x000E -#define L2VOLTAGE 0x0010 -#define L3VOLTAGE 0x0012 - -#define L1CURRENT 0x0016 -#define L2CURRENT 0x0018 -#define L3CURRENT 0x001A - -#define TOTALACTIVEPOWER 0x001C - -// Example Data (Object) Dictionary for Modbus parameters: -// The CID field in the table must be unique. -// Modbus Slave Addr field defines slave address of the device with correspond parameter. -// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such). -// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the characteristic accordingly. -// The Instance Offset defines offset in the appropriate parameter structure that will be used as instance to save parameter value. -// Data Type, Data Size specify type of the characteristic and its data size. -// Parameter Options field specifies the options that can be used to process parameter value (limits or masks). -// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc). const mb_parameter_descriptor_t device_parameters_orno516[] = { - // { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode} - - {CID_HOLD_DATA_0, STR("L1"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L1CURRENT, 2, - HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_1, STR("L2"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L2CURRENT, 2, - HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}, - - {CID_HOLD_DATA_2, STR("L3"), STR("A"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, L3CURRENT, 2, - HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ} + {CID_L1_CURRENT, STR("L1 Current"), STR("A"), 1, MB_PARAM_HOLDING, L1CURRENT, 2, + HOLD_OFFSET(l1_current), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}, + {CID_L2_CURRENT, STR("L2 Current"), STR("A"), 1, MB_PARAM_HOLDING, L2CURRENT, 2, + HOLD_OFFSET(l2_current), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}, + {CID_L3_CURRENT, STR("L3 Current"), STR("A"), 1, MB_PARAM_HOLDING, L3CURRENT, 2, + HOLD_OFFSET(l3_current), PARAM_TYPE_FLOAT, 4, OPTS(-1000, 1000, 0.1), PAR_PERMS_READ}, + {CID_L1_VOLTAGE, STR("L1 Voltage"), STR("V"), 1, MB_PARAM_HOLDING, L1VOLTAGE, 2, + HOLD_OFFSET(l1_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + {CID_L2_VOLTAGE, STR("L2 Voltage"), STR("V"), 1, MB_PARAM_HOLDING, L2VOLTAGE, 2, + HOLD_OFFSET(l2_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + {CID_L3_VOLTAGE, STR("L3 Voltage"), STR("V"), 1, MB_PARAM_HOLDING, L3VOLTAGE, 2, + HOLD_OFFSET(l3_voltage), PARAM_TYPE_FLOAT, 4, OPTS(0, 300, 0.1), PAR_PERMS_READ}, + {CID_TOTAL_ACTIVE_POWER, STR("Total Active Power"), STR("W"), 1, MB_PARAM_HOLDING, TOTALACTIVEPOWER, 2, + HOLD_OFFSET(total_active_power), PARAM_TYPE_FLOAT, 4, OPTS(0, 100000, 1), PAR_PERMS_READ} }; -// Calculate number of parameters in the table -const uint16_t num_device_parameters_orno516 = (sizeof(device_parameters_orno516) / sizeof(device_parameters_orno516[0])); +const uint16_t num_device_parameters_orno516 = sizeof(device_parameters_orno516) / sizeof(device_parameters_orno516[0]); -// The function to get pointer to parameter storage (instance) according to parameter description table -static void *master_get_param_data_orno516(const mb_parameter_descriptor_t *param_descriptor) -{ - assert(param_descriptor != NULL); - void *instance_ptr = NULL; - if (param_descriptor->param_offset != 0) - { - switch (param_descriptor->mb_param_type) - { - case MB_PARAM_HOLDING: - instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1); - break; - case MB_PARAM_INPUT: - instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1); - break; - case MB_PARAM_COIL: - instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1); - break; - case MB_PARAM_DISCRETE: - instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1); - break; - default: - instance_ptr = NULL; - break; - } - } - else - { - ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", (unsigned)param_descriptor->cid); - assert(instance_ptr != NULL); - } - return instance_ptr; -} - -// Float - Mid-Little Endian (CDAB) -float ReverseFloat_orno516(const float inFloat) -{ +float ReverseFloat(const float inFloat) { float retVal; char *floatToConvert = (char *)&inFloat; char *returnFloat = (char *)&retVal; - - // swap the bytes into a temporary buffer returnFloat[0] = floatToConvert[2]; returnFloat[1] = floatToConvert[3]; returnFloat[2] = floatToConvert[0]; returnFloat[3] = floatToConvert[1]; - return retVal; } -static void serial_mdb_task_func_orno516(void *param) -{ - ESP_LOGI(TAG, "serial_mdb_task_func_orno516"); - esp_err_t err = ESP_OK; - - float maxcurrent = 0; - float l1current = 0; - float l2current = 0; - float l3current = 0; - int error_count = 0; - - bool alarm_state = false; - const mb_parameter_descriptor_t *param_descriptor = NULL; - - ESP_LOGI(TAG, "Start modbus..."); - - while (true) - { - // Read all found characteristics from slave(s) - for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) - { - // Get data from parameters description table - // and use this information to fill the characteristics description table - // and having all required fields in just one table - err = mbc_master_get_cid_info(cid, ¶m_descriptor); - if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) - { - void *temp_data_ptr = master_get_param_data_orno516(param_descriptor); - uint8_t type = 0; - - err = mbc_master_get_parameter(cid, (char *)param_descriptor->param_key, - (uint8_t *)temp_data_ptr, &type); - - if (err == ESP_OK) - { - error_count = 0; - meterState = true; - - if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) || - (param_descriptor->mb_param_type == MB_PARAM_INPUT)) - { - float value = *(float *)temp_data_ptr; - value = ReverseFloat_orno516(value); - - switch (cid) - { - case 0: - maxcurrent = 0; - l1current = 0; - l2current = 0; - l3current = 0; - - l1current = value; - break; - case 1: - l2current = value; - break; - case 2: - l3current = value; - break; - default: - // code block - } - - ESP_LOGD(TAG, "Characteristic #%u %s (%s) value = %f (0x%" PRIx32 ") read successful.", - param_descriptor->cid, - param_descriptor->param_key, - param_descriptor->param_units, - value, - *(uint32_t *)temp_data_ptr); - - if (((value > param_descriptor->param_opts.max) || - (value < param_descriptor->param_opts.min))) - { - alarm_state = true; - break; - } - } - } - else - { - if (error_count > 3 && !meterTest) - { - meterState = false; - vTaskDelay(ERROR_TIMEOUT_MS * error_count); // timeout between polls - } - else - { - error_count++; - } - - ESP_LOGE(TAG, "Characteristic #%u (%s) read fail, err = 0x%x (%s).", - param_descriptor->cid, - param_descriptor->param_key, - (int)err, - (char *)esp_err_to_name(err)); - } - - vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls - } - } - - vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS); - } - - if (alarm_state) - { - ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid); - } - else - { - ESP_LOGE(TAG, "Alarm is not triggered after %u retries.", MASTER_MAX_RETRY); - } - ESP_LOGI(TAG, "Destroy master..."); - ESP_ERROR_CHECK(mbc_master_destroy()); +static void *get_param_ptr(const mb_parameter_descriptor_t *param) { + if (!param || param->param_offset == 0) return NULL; + return ((uint8_t *)&holding_reg_params + param->param_offset - 1); } -// Modbus master initialization -static esp_err_t master_init_orno516(void) -{ - // Initialize and start Modbus controller + +static void meter_orno516_post_event(float *voltage, float *current, int *power) { + meter_event_data_t evt = { + .source = "GRID", + .frequency = 0.0f, // ORNO-516 não fornece + .power_factor = 0.0f, // idem + .total_energy = 0.0f // idem + }; + memcpy(evt.vrms, voltage, sizeof(evt.vrms)); + memcpy(evt.irms, current, sizeof(evt.irms)); + memcpy(evt.watt, power, sizeof(evt.watt)); + + esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, + &evt, sizeof(evt), pdMS_TO_TICKS(10)); + + if (err != ESP_OK) { + ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err)); + } +} + +static void serial_mdb_task(void *param) { + esp_err_t err; + const mb_parameter_descriptor_t *desc = NULL; + float voltage[3] = {0}, current[3] = {0}; + int power[3] = {0}; + + while (1) { + for (uint16_t cid = 0; cid < num_device_parameters_orno516; cid++) { + err = mbc_master_get_cid_info(cid, &desc); + if (err != ESP_OK || !desc) continue; + + void *data_ptr = get_param_ptr(desc); + uint8_t type = 0; + err = mbc_master_get_parameter(cid, (char *)desc->param_key, (uint8_t *)data_ptr, &type); + + if (err == ESP_OK && data_ptr) { + float val = ReverseFloat(*(float *)data_ptr); + ESP_LOGI(TAG, "%s: %.2f %s", desc->param_key, val, desc->param_units); + + switch (cid) { + case CID_L1_VOLTAGE: voltage[0] = val; break; + case CID_L2_VOLTAGE: voltage[1] = val; break; + case CID_L3_VOLTAGE: voltage[2] = val; break; + case CID_L1_CURRENT: current[0] = val; break; + case CID_L2_CURRENT: current[1] = val; break; + case CID_L3_CURRENT: current[2] = val; break; + case CID_TOTAL_ACTIVE_POWER: + power[0] = (int)(val / 3); + power[1] = (int)(val / 3); + power[2] = (int)(val / 3); + break; + default: + break; + } + } else { + ESP_LOGE(TAG, "CID %u (%s) read failed: %s", cid, desc->param_key, esp_err_to_name(err)); + } + + vTaskDelay(POLL_INTERVAL); + } + + meter_orno516_post_event(voltage, current, power); + vTaskDelay(UPDATE_INTERVAL); + } +} + + +esp_err_t meter_orno516_init(void) { + if (is_initialized) { + ESP_LOGW(TAG, "Already initialized"); + return ESP_ERR_INVALID_STATE; + } + + // Tenta apagar UART apenas se estiver inicializada + if (uart_is_driver_installed(MB_PORT_NUM)) { + uart_driver_delete(MB_PORT_NUM); + ESP_LOGI(TAG, "UART driver deleted"); + } + + mbc_master_destroy(); // OK mesmo que não esteja inicializado + mb_communication_info_t comm = { - //.slave_addr = 1, .port = MB_PORT_NUM, .mode = MB_MODE_RTU, .baudrate = MB_DEV_SPEED, - .parity = UART_PARITY_EVEN}; - void *master_handler = NULL; + .parity = UART_PARITY_EVEN + }; - esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler); - MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG, - "mb controller initialization fail."); - MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller initialization fail, returns(0x%x).", (int)err); - err = mbc_master_setup((void *)&comm); - MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller setup fail, returns(0x%x).", (int)err); + void *handler = NULL; + ESP_ERROR_CHECK(mbc_master_init(MB_PORT_SERIAL_MASTER, &handler)); + ESP_ERROR_CHECK(mbc_master_setup(&comm)); + ESP_ERROR_CHECK(uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, MB_UART_RTS, UART_PIN_NO_CHANGE)); + ESP_ERROR_CHECK(mbc_master_start()); + ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX)); + vTaskDelay(pdMS_TO_TICKS(5)); + ESP_ERROR_CHECK(mbc_master_set_descriptor(device_parameters_orno516, num_device_parameters_orno516)); - // Set UART pin numbers - err = uart_set_pin(MB_PORT_NUM, MB_UART_TXD, MB_UART_RXD, - MB_UART_RTS, UART_PIN_NO_CHANGE); - MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb serial set pin failure, uart_set_pin() returned (0x%x).", (int)err); - - err = mbc_master_start(); - MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller start fail, returned (0x%x).", (int)err); - - // Set driver mode to Half Duplex - err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX); - MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb serial set mode failure, uart_set_mode() returned (0x%x).", (int)err); - - vTaskDelay(5); - err = mbc_master_set_descriptor(&device_parameters_orno516[0], num_device_parameters_orno516); - MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG, - "mb controller set descriptor fail, returns(0x%x).", (int)err); - ESP_LOGI(TAG, "Modbus master stack initialized..."); - return err; + is_initialized = true; + return ESP_OK; } -/** - * @brief Set meter model - * - */ -void serial_mdb_set_model_orno516(bool _enabled) -{ - enabled = _enabled; -} - -/** - * @brief Set meter state - * - */ -bool serial_mdb_get_meter_state_orno516() -{ - return meterState; -} - -/** - * @brief Set meter test state - * - */ -void serial_mdb_set_meter_test_orno516(bool _meterTest) -{ - meterTest = _meterTest; -} - - -esp_err_t serial_mdb_start_orno516() -{ - ESP_LOGI(TAG, "Starting MDB Serial"); - - // Call the initialization function and check for errors - esp_err_t err = master_init_orno516(); - ESP_ERROR_CHECK(err); // Check if there was an error during initialization - - // Create the task to handle the MDB serial communication - xTaskCreate(serial_mdb_task_func_orno516, "serial_mdb_task_orno516", 4 * 1024, NULL, 5, &serial_mdb_task); - - return err; -} - - -void serial_mdb_stop_orno516(void) -{ - ESP_LOGI(TAG, "Stopping"); - - if (serial_mdb_task) - { - vTaskDelete(serial_mdb_task); - serial_mdb_task = NULL; +esp_err_t meter_orno516_start(void) { + if (!is_initialized) { + ESP_LOGE(TAG, "Not initialized"); + return ESP_ERR_INVALID_STATE; } - uart_driver_delete(MB_PORT_NUM); + if (meter_task == NULL) { + xTaskCreate(serial_mdb_task, "meter_orno516_task", 4096, NULL, 3, &meter_task); + ESP_LOGI(TAG, "Task started"); + } + + return ESP_OK; +} + +void meter_orno516_stop(void) { + if (!is_initialized) { + ESP_LOGW(TAG, "Not initialized, skipping stop"); + return; + } + + if (meter_task) { + vTaskDelete(meter_task); + meter_task = NULL; + ESP_LOGI(TAG, "Task stopped"); + } + + mbc_master_destroy(); + + if (uart_is_driver_installed(MB_PORT_NUM)) { + uart_driver_delete(MB_PORT_NUM); + ESP_LOGI(TAG, "UART driver deleted"); + } + + is_initialized = false; + ESP_LOGI(TAG, "Meter ORNO-516 cleaned up"); } diff --git a/components/meter_manager/driver/meter_orno/meter_orno516.h b/components/meter_manager/driver/meter_orno/meter_orno516.h index c85a6f5..42f8a5c 100755 --- a/components/meter_manager/driver/meter_orno/meter_orno516.h +++ b/components/meter_manager/driver/meter_orno/meter_orno516.h @@ -10,61 +10,20 @@ * * @return esp_err_t Retorna ESP_OK se a inicialização for bem-sucedida, caso contrário retorna um erro. */ -esp_err_t meter_init_orno516(void); +esp_err_t meter_orno516_init(void); /** * @brief Inicia a tarefa de leitura de dados do medidor ORNO 516. * * @return esp_err_t Retorna ESP_OK se a tarefa for iniciada com sucesso, caso contrário retorna um erro. */ -esp_err_t meter_start_orno516(void); +esp_err_t meter_orno516_start(void); /** * @brief Para a tarefa de leitura e limpa os dados internos do medidor ORNO 516. */ -void meter_stop_orno516(void); +void meter_orno516_stop(void); -/** - * @brief Verifica se o medidor ORNO 516 está em execução. - * - * @return true Se a tarefa estiver ativa, false caso contrário. - */ -bool meter_is_running_orno516(void); - -/** - * @brief Limpa os dados armazenados no medidor ORNO 516 (zera todos os valores). - */ -void meter_clear_data_orno516(void); - -// ----- Leituras por fase (L1, L2, L3) ----- - -// Tensão RMS (em volts) -float meter_get_vrms_l1_orno516(void); -float meter_get_vrms_l2_orno516(void); -float meter_get_vrms_l3_orno516(void); - -// Corrente RMS (em amperes) -float meter_get_irms_l1_orno516(void); -float meter_get_irms_l2_orno516(void); -float meter_get_irms_l3_orno516(void); - -// Potência ativa (W) -int meter_get_watt_l1_orno516(void); -int meter_get_watt_l2_orno516(void); -int meter_get_watt_l3_orno516(void); - -// Potência reativa (VAR) -int meter_get_var_l1_orno516(void); -int meter_get_var_l2_orno516(void); -int meter_get_var_l3_orno516(void); - -// Potência aparente (VA) -int meter_get_va_l1_orno516(void); -int meter_get_va_l2_orno516(void); -int meter_get_va_l3_orno516(void); - -// (Opcional) contador de watchdog para diagnóstico -uint32_t meter_get_watchdog_counter_orno516(void); #ifdef __cplusplus } diff --git a/components/meter_manager/driver/meter_orno/modbus_params.h b/components/meter_manager/driver/meter_orno/modbus_params.h index e1b2b90..7b4755b 100755 --- a/components/meter_manager/driver/meter_orno/modbus_params.h +++ b/components/meter_manager/driver/meter_orno/modbus_params.h @@ -4,83 +4,72 @@ * SPDX-License-Identifier: Apache-2.0 */ -/*===================================================================================== - * Description: - * The Modbus parameter structures used to define Modbus instances that - * can be addressed by Modbus protocol. Define these structures per your needs in - * your application. Below is just an example of possible parameters. - *====================================================================================*/ #ifndef _DEVICE_PARAMS #define _DEVICE_PARAMS #include -// This file defines structure of modbus parameters which reflect correspond modbus address space -// for each modbus register type (coils, discreet inputs, holding registers, input registers) #pragma pack(push, 1) -typedef struct -{ - uint8_t discrete_input0:1; - uint8_t discrete_input1:1; - uint8_t discrete_input2:1; - uint8_t discrete_input3:1; - uint8_t discrete_input4:1; - uint8_t discrete_input5:1; - uint8_t discrete_input6:1; - uint8_t discrete_input7:1; + +// Discrete Inputs +typedef struct { + uint8_t discrete_input0 : 1; + uint8_t discrete_input1 : 1; + uint8_t discrete_input2 : 1; + uint8_t discrete_input3 : 1; + uint8_t discrete_input4 : 1; + uint8_t discrete_input5 : 1; + uint8_t discrete_input6 : 1; + uint8_t discrete_input7 : 1; uint8_t discrete_input_port1; uint8_t discrete_input_port2; } discrete_reg_params_t; -#pragma pack(pop) -#pragma pack(push, 1) -typedef struct -{ +// Coils +typedef struct { uint8_t coils_port0; uint8_t coils_port1; uint8_t coils_port2; } coil_reg_params_t; -#pragma pack(pop) -#pragma pack(push, 1) -typedef struct -{ - float input_data0; // 0 - float input_data1; // 2 - float input_data2; // 4 - float input_data3; // 6 - uint16_t data[150]; // 8 + 150 = 158 - float input_data4; // 158 +// Input Registers (pode manter caso use em outro driver) +typedef struct { + float input_data0; + float input_data1; + float input_data2; + float input_data3; + uint16_t data[150]; + float input_data4; float input_data5; float input_data6; float input_data7; uint16_t data_block1[150]; } input_reg_params_t; -#pragma pack(pop) -#pragma pack(push, 1) -typedef struct -{ - uint32_t holding_data0; - uint32_t holding_data1; - uint32_t holding_data2; - uint32_t holding_data3; - uint32_t holding_data4; - uint32_t holding_data5; - uint32_t holding_data6; - uint32_t holding_data7; - uint32_t holding_data8; - uint32_t holding_data9; - uint32_t holding_data10; - uint32_t holding_data11; - uint32_t holding_data12; - uint32_t holding_data13; +// Holding Registers (ajustado para os campos usados no ORNO 516) +typedef struct { + float l1_current; // 0x0016 + float l2_current; // 0x0018 + float l3_current; // 0x001A + + float l1_voltage; // 0x000E + float l2_voltage; // 0x0010 + float l3_voltage; // 0x0012 + + float total_active_power; // 0x001C + float total_reactive_power; + float active_power; + float apparent_power; + float reactive_power; } holding_reg_params_t; + + #pragma pack(pop) +// Instâncias globais das estruturas extern holding_reg_params_t holding_reg_params; extern input_reg_params_t input_reg_params; extern coil_reg_params_t coil_reg_params; extern discrete_reg_params_t discrete_reg_params; -#endif // !defined(_DEVICE_PARAMS) +#endif // !_DEVICE_PARAMS diff --git a/components/meter_manager/driver/meter_zigbee/meter_zigbee.c b/components/meter_manager/driver/meter_zigbee/meter_zigbee.c index 862640d..4599080 100755 --- a/components/meter_manager/driver/meter_zigbee/meter_zigbee.c +++ b/components/meter_manager/driver/meter_zigbee/meter_zigbee.c @@ -7,6 +7,7 @@ #include "esp_system.h" #include "driver/uart.h" #include "driver/gpio.h" +#include "meter_events.h" #define TAG "meter_zigbee" @@ -21,19 +22,15 @@ #define ATTR_CURRENT_L1 0x0006 #define ATTR_CURRENT_L2 0x0007 #define ATTR_CURRENT_L3 0x0008 - #define ATTR_VOLTAGE_L1 0x0266 #define ATTR_CURRENT_L1_ALT 0x0267 #define ATTR_POWER_L1 0x0268 - #define ATTR_VOLTAGE_L2 0x0269 #define ATTR_CURRENT_L2_ALT 0x026A #define ATTR_POWER_L2 0x026B - #define ATTR_VOLTAGE_L3 0x026C #define ATTR_CURRENT_L3_ALT 0x026D #define ATTR_POWER_L3 0x026E - #define ATTR_FREQUENCY 0x0265 #define ATTR_POWER_FACTOR 0x020F #define ATTR_TOTAL_ENERGY 0x0201 @@ -55,100 +52,114 @@ typedef struct { float total_energy; } meter_zigbee_data_t; +static bool phase_updated[PHASE_COUNT] = {false, false, false}; + + static meter_zigbee_data_t meter_data = {0}; static SemaphoreHandle_t meter_mutex = NULL; -static TaskHandle_t meter_task = NULL; +static TaskHandle_t meter_zigbee_task = NULL; -// ---------- Utils ---------- +static void meter_zigbee_post_event(void) { + meter_event_data_t evt = { + .source = "GRID", + .frequency = meter_data.frequency, + .power_factor = meter_data.power_factor, + .total_energy = meter_data.total_energy + }; -static inline float decode_float(const uint8_t *buf) { - return (buf[9] + (buf[8] << 8) + (buf[7] << 16)) / 100.0f; -} + memcpy(evt.vrms, meter_data.vrms, sizeof(evt.vrms)); + memcpy(evt.irms, meter_data.irms, sizeof(evt.irms)); + memcpy(evt.watt, meter_data.watt, sizeof(evt.watt)); -static float meter_data_get_float(const float *arr, uint8_t phase) { - float val = 0.0f; - if (phase >= PHASE_COUNT) return 0; - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - val = arr[phase]; - xSemaphoreGive(meter_mutex); - } - return val; -} + esp_err_t err = esp_event_post(METER_EVENT, + METER_EVENT_DATA_READY, + &evt, + sizeof(evt), + pdMS_TO_TICKS(10)); -static int meter_data_get_int(const int *arr, uint8_t phase) { - int val = 0; - if (phase >= PHASE_COUNT) return 0; - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - val = arr[phase]; - xSemaphoreGive(meter_mutex); - } - return val; -} - -static void meter_data_clear(void) { - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - memset(&meter_data, 0, sizeof(meter_data)); - xSemaphoreGive(meter_mutex); + if (err != ESP_OK) { + ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err)); } } -// ---------- Frame Handler ---------- -static void handle_zigbee_frame(const uint8_t *buf) { - uint16_t attr = buf[1] | (buf[2] << 8); - uint8_t size = buf[4]; +static void handle_zigbee_frame(const uint8_t *buf, size_t len) { + ESP_LOGI(TAG, "Received UART frame (%d bytes):", len); + ESP_LOG_BUFFER_HEX(TAG, buf, len); - if (size != 8) { - ESP_LOGW(TAG, "Unexpected data size: %d", size); + if (len < RX_FRAME_SIZE) { + ESP_LOGW(TAG, "Invalid frame: too short (len = %d)", len); return; } - float value = decode_float(buf); - ESP_LOGI(TAG, "Attr 0x%04X = %.2f", attr, value); + uint16_t attr = buf[2] | (buf[3] << 8); + uint8_t size = buf[5]; + + if (size != 8) { + ESP_LOGW(TAG, "Unsupported payload size: %d", size); + return; + } + + uint16_t volt_raw = (buf[6] << 8) | buf[7]; + uint32_t current_raw = (buf[8] << 16) | (buf[9] << 8) | buf[10]; + uint32_t power_raw = (buf[11] << 16) | (buf[12] << 8) | buf[13]; + + float volt = volt_raw / 10.0f; + float current = current_raw / 100.0f; + float power = power_raw / 1000.0f; + + ESP_LOGI(TAG, "Parsed Attr 0x%04X: V=%.1fV I=%.2fA P=%.1fW", attr, volt, current, power); if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { switch (attr) { case ATTR_CURRENT_L1: case ATTR_CURRENT_L1_ALT: - meter_data.irms[0] = value; + meter_data.irms[PHASE_L1] = current; + meter_data.vrms[PHASE_L1] = volt; + meter_data.watt[PHASE_L1] = (int)power; + phase_updated[PHASE_L1] = true; break; - case ATTR_CURRENT_L2: case ATTR_CURRENT_L2_ALT: - meter_data.irms[1] = value; + meter_data.irms[PHASE_L2] = current; + meter_data.vrms[PHASE_L2] = volt; + meter_data.watt[PHASE_L2] = (int)power; + phase_updated[PHASE_L2] = true; break; - case ATTR_CURRENT_L3: case ATTR_CURRENT_L3_ALT: - meter_data.irms[2] = value; + meter_data.irms[PHASE_L3] = current; + meter_data.vrms[PHASE_L3] = volt; + meter_data.watt[PHASE_L3] = (int)power; + phase_updated[PHASE_L3] = true; + break; + case ATTR_POWER_FACTOR: + meter_data.power_factor = current; + break; + case ATTR_FREQUENCY: + meter_data.frequency = current; + break; + case ATTR_TOTAL_ENERGY: + meter_data.total_energy = current; break; - - case ATTR_VOLTAGE_L1: meter_data.vrms[0] = value; break; - case ATTR_VOLTAGE_L2: meter_data.vrms[1] = value; break; - case ATTR_VOLTAGE_L3: meter_data.vrms[2] = value; break; - - case ATTR_POWER_L1: meter_data.watt[0] = (int)value; break; - case ATTR_POWER_L2: meter_data.watt[1] = (int)value; break; - case ATTR_POWER_L3: meter_data.watt[2] = (int)value; break; - - case ATTR_POWER_FACTOR: meter_data.power_factor = value; break; - case ATTR_FREQUENCY: meter_data.frequency = value; break; - case ATTR_TOTAL_ENERGY: meter_data.total_energy = value; break; - default: ESP_LOGW(TAG, "Unknown attr: 0x%04X", attr); break; } xSemaphoreGive(meter_mutex); } + + // Verifica se todas as 3 fases foram atualizadas + if (phase_updated[PHASE_L1] && phase_updated[PHASE_L2] && phase_updated[PHASE_L3]) { + meter_zigbee_post_event(); + memset(phase_updated, 0, sizeof(phase_updated)); + } } -// ---------- Task ---------- - -static void meter_task_func(void *param) { +static void meter_zigbee_task_func(void *param) { uint8_t *buf = malloc(RX_FRAME_SIZE); if (!buf) { - ESP_LOGE(TAG, "Memory allocation failed"); + ESP_LOGE(TAG, "Failed to allocate buffer"); vTaskDelete(NULL); return; } @@ -156,9 +167,13 @@ static void meter_task_func(void *param) { ESP_LOGI(TAG, "Zigbee meter task started"); while (1) { - int len = uart_read_bytes(UART_PORT, buf, RX_FRAME_SIZE, pdMS_TO_TICKS(1000)); - if (len >= 10) { - handle_zigbee_frame(buf); + int len = uart_read_bytes(UART_PORT, buf, RX_FRAME_SIZE, pdMS_TO_TICKS(5000)); + if (len == RX_FRAME_SIZE) { + handle_zigbee_frame(buf, len); + } else if (len == 0) { + ESP_LOGD(TAG, "UART timeout with no data"); + } else { + ESP_LOGW(TAG, "Incomplete frame received (%d bytes)", len); } } @@ -166,9 +181,7 @@ static void meter_task_func(void *param) { vTaskDelete(NULL); } -// ---------- Public API (meter.h) ---------- - -esp_err_t meter_init(void) { +esp_err_t meter_zigbee_init(void) { ESP_LOGI(TAG, "Initializing Zigbee meter"); if (!meter_mutex) { @@ -176,8 +189,6 @@ esp_err_t meter_init(void) { if (!meter_mutex) return ESP_ERR_NO_MEM; } - meter_data_clear(); - uart_config_t config = { .baud_rate = 115200, .data_bits = UART_DATA_8_BITS, @@ -194,17 +205,17 @@ esp_err_t meter_init(void) { return ESP_OK; } -esp_err_t meter_start(void) { - if (meter_task) return ESP_ERR_INVALID_STATE; +esp_err_t meter_zigbee_start(void) { + if (meter_zigbee_task) return ESP_ERR_INVALID_STATE; - xTaskCreate(meter_task_func, "meter_zigbee_task", 4096, NULL, 5, &meter_task); + xTaskCreate(meter_zigbee_task_func, "meter_zigbee_task", 4096, NULL, 3, &meter_zigbee_task); return ESP_OK; } -void meter_stop(void) { - if (meter_task) { - vTaskDelete(meter_task); - meter_task = NULL; +void meter_zigbee_stop(void) { + if (meter_zigbee_task) { + vTaskDelete(meter_zigbee_task); + meter_zigbee_task = NULL; } uart_driver_delete(UART_PORT); @@ -215,63 +226,6 @@ void meter_stop(void) { } } -bool meter_is_running(void) { - return meter_task != NULL; -} - -void meter_clear_data(void) { - meter_data_clear(); -} - -// ---------- RMS Current ---------- -float meter_get_irms_l1(void) { return meter_data_get_float(meter_data.irms, PHASE_L1); } -float meter_get_irms_l2(void) { return meter_data_get_float(meter_data.irms, PHASE_L2); } -float meter_get_irms_l3(void) { return meter_data_get_float(meter_data.irms, PHASE_L3); } - -// ---------- RMS Voltage ---------- -float meter_get_vrms_l1(void) { return meter_data_get_float(meter_data.vrms, PHASE_L1); } -float meter_get_vrms_l2(void) { return meter_data_get_float(meter_data.vrms, PHASE_L2); } -float meter_get_vrms_l3(void) { return meter_data_get_float(meter_data.vrms, PHASE_L3); } - -// ---------- Active Power ---------- -int meter_get_watt_l1(void) { return meter_data_get_int(meter_data.watt, PHASE_L1); } -int meter_get_watt_l2(void) { return meter_data_get_int(meter_data.watt, PHASE_L2); } -int meter_get_watt_l3(void) { return meter_data_get_int(meter_data.watt, PHASE_L3); } - -// ---------- Reactive Power ---------- -int meter_get_var_l1(void) { return meter_data_get_int(meter_data.var, PHASE_L1); } -int meter_get_var_l2(void) { return meter_data_get_int(meter_data.var, PHASE_L2); } -int meter_get_var_l3(void) { return meter_data_get_int(meter_data.var, PHASE_L3); } - -// ---------- Apparent Power ---------- -int meter_get_va_l1(void) { return meter_data_get_int(meter_data.va, PHASE_L1); } -int meter_get_va_l2(void) { return meter_data_get_int(meter_data.va, PHASE_L2); } -int meter_get_va_l3(void) { return meter_data_get_int(meter_data.va, PHASE_L3); } - -// ---------- Extra Data ---------- -float meter_get_frequency(void) { - float v = 0; - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - v = meter_data.frequency; - xSemaphoreGive(meter_mutex); - } - return v; -} - -float meter_get_power_factor(void) { - float v = 0; - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - v = meter_data.power_factor; - xSemaphoreGive(meter_mutex); - } - return v; -} - -float meter_get_total_energy(void) { - float v = 0; - if (xSemaphoreTake(meter_mutex, pdMS_TO_TICKS(10)) == pdTRUE) { - v = meter_data.total_energy; - xSemaphoreGive(meter_mutex); - } - return v; +bool meter_zigbee_is_running(void) { + return meter_zigbee_task != NULL; } diff --git a/components/meter_manager/driver/meter_zigbee/meter_zigbee.h b/components/meter_manager/driver/meter_zigbee/meter_zigbee.h index 635e844..2bc2e48 100755 --- a/components/meter_manager/driver/meter_zigbee/meter_zigbee.h +++ b/components/meter_manager/driver/meter_zigbee/meter_zigbee.h @@ -13,85 +13,20 @@ extern "C" { * * @return ESP_OK se a inicialização for bem-sucedida, erro caso contrário. */ -esp_err_t meter_init_zigbee(void); +esp_err_t meter_zigbee_init(void); /** * @brief Inicia a tarefa de leitura dos dados do medidor Zigbee. * * @return ESP_OK se a tarefa for iniciada com sucesso, erro caso contrário. */ -esp_err_t meter_start_zigbee(void); +esp_err_t meter_zigbee_start(void); /** * @brief Interrompe a tarefa e limpa recursos (UART, mutex, etc.). */ -void meter_stop_zigbee(void); +void meter_zigbee_stop(void); -/** - * @brief Verifica se o medidor Zigbee está em execução. - * - * @return true se a tarefa está ativa, false se não. - */ -bool meter_is_running_zigbee(void); - -/** - * @brief Limpa todos os dados armazenados em memória. - */ -void meter_clear_data_zigbee(void); - -// ---------------------- -// Leituras por fase (L1, L2, L3) -// ---------------------- - -// Corrente RMS (em amperes) -float meter_get_irms_l1_zigbee(void); -float meter_get_irms_l2_zigbee(void); -float meter_get_irms_l3_zigbee(void); - -// Tensão RMS (em volts) -float meter_get_vrms_l1_zigbee(void); -float meter_get_vrms_l2_zigbee(void); -float meter_get_vrms_l3_zigbee(void); - -// Potência ativa (W) -int meter_get_watt_l1_zigbee(void); -int meter_get_watt_l2_zigbee(void); -int meter_get_watt_l3_zigbee(void); - -// Potência reativa (VAR) -int meter_get_var_l1_zigbee(void); -int meter_get_var_l2_zigbee(void); -int meter_get_var_l3_zigbee(void); - -// Potência aparente (VA) -int meter_get_va_l1_zigbee(void); -int meter_get_va_l2_zigbee(void); -int meter_get_va_l3_zigbee(void); - -// ---------------------- -// Dados adicionais -// ---------------------- - -/** - * @brief Retorna a frequência da rede em Hz. - * - * @return Valor da frequência da rede em Hz. - */ -float meter_get_frequency_zigbee(void); - -/** - * @brief Retorna o fator de potência médio. - * - * @return Valor do fator de potência médio. - */ -float meter_get_power_factor_zigbee(void); - -/** - * @brief Retorna a energia total acumulada (kWh ou Wh, dependendo do dispositivo). - * - * @return Valor da energia total acumulada. - */ -float meter_get_total_energy_zigbee(void); #ifdef __cplusplus } diff --git a/components/meter_manager/include/meter_events.h b/components/meter_manager/include/meter_events.h new file mode 100644 index 0000000..05b7e63 --- /dev/null +++ b/components/meter_manager/include/meter_events.h @@ -0,0 +1,38 @@ +#ifndef METER_EVENTS_H +#define METER_EVENTS_H + +#include "esp_event.h" +#include "meter_manager.h" // Para meter_type_t + +#ifdef __cplusplus +extern "C" { +#endif + +// Base de eventos dos medidores +ESP_EVENT_DECLARE_BASE(METER_EVENT); + +// IDs de eventos emitidos por medidores +typedef enum { + METER_EVENT_DATA_READY = 0, + METER_EVENT_ERROR, + METER_EVENT_STARTED, + METER_EVENT_STOPPED +} meter_event_id_t; + +// Estrutura de dados enviados com METER_EVENT_DATA_READY +typedef struct { + const char *source; // "GRID" ou "EVSE" + float vrms[3]; // Tensão por fase + float irms[3]; // Corrente por fase + int watt[3]; // Potência ativa por fase + float frequency; // Frequência da rede (Hz) + float power_factor; // Fator de potência + float total_energy; // Energia acumulada (kWh) +} meter_event_data_t; + + +#ifdef __cplusplus +} +#endif + +#endif // METER_EVENTS_H diff --git a/components/meter_manager/include/meter_manager.h b/components/meter_manager/include/meter_manager.h index a30e4b3..e270d6d 100755 --- a/components/meter_manager/include/meter_manager.h +++ b/components/meter_manager/include/meter_manager.h @@ -2,28 +2,66 @@ #define METER_MANAGER_H #include "esp_err.h" +#include // Para garantir que 'bool' seja reconhecido // Definindo tipos de medidores possíveis para EVSE e Grid typedef enum { - METER_TYPE_NONE, // Nenhum medidor - METER_TYPE_EVSE_ADE7758, // EVSE com ADE7758 - METER_TYPE_GRID_ORNO513, // Grid com ORNO 513 - METER_TYPE_GRID_ORNO516, // Grid com ORNO 516 - METER_TYPE_GRID_ZIGBEE // Grid com Zigbee + METER_TYPE_NONE, // Nenhum Medidor + METER_TYPE_ADE7758, // ADE7758 + METER_TYPE_ORNO513, // ORNO 513 + METER_TYPE_ORNO516, // ORNO 516 + METER_TYPE_MONO_ZIGBEE, // Medidor Zigbee (Mono) + METER_TYPE_TRIF_ZIGBEE // Medidor Zigbee (Trifásico) } meter_type_t; -// Funções para inicializar e gerenciar o medidor EVSE (pode ser ADE7758) -esp_err_t meter_manager_init_evse(meter_type_t evse_type); // Inicializa o medidor EVSE (ex: ADE7758) -esp_err_t meter_manager_start_evse(meter_type_t evse_type); // Inicia o EVSE com o tipo especificado -esp_err_t meter_manager_stop_evse(void); // Para o EVSE +/** + * @brief Funções para gerenciar o medidor EVSE (ex: ADE7758). + */ -// Funções para inicializar e gerenciar o medidor Grid (pode ser ORNO 513, ORNO 516 ou Zigbee) -esp_err_t meter_manager_init_grid(meter_type_t grid_type); // Inicializa o medidor Grid (ORNO 513, ORNO 516, Zigbee) -esp_err_t meter_manager_start_grid(meter_type_t grid_type); // Inicia o medidor Grid com o tipo especificado -esp_err_t meter_manager_stop_grid(void); // Para o medidor Grid +// Inicializa o medidor EVSE com o tipo especificado (ex: ADE7758) +esp_err_t meter_manager_evse_init(void); -// Funções para ler dados dos medidores -esp_err_t meter_manager_read_current(meter_type_t meter_type, float *current); // Lê a corrente do medidor -esp_err_t meter_manager_read_voltage(meter_type_t meter_type, float *voltage); // Lê a tensão do medidor +// Inicia o medidor EVSE com o tipo especificado +esp_err_t meter_manager_evse_start(void); + +// Para o medidor EVSE +esp_err_t meter_manager_evse_stop(void); + +// Verifica se o medidor EVSE está habilitado +bool meter_manager_evse_is_enabled(void); + +// Define o modelo do medidor EVSE (ADE7758, etc) +esp_err_t meter_manager_evse_set_model(meter_type_t meter_type); + +// Retorna o modelo do medidor EVSE (ADE7758, etc) +meter_type_t meter_manager_evse_get_model(void); + + +/** + * @brief Funções para gerenciar o medidor Grid (ORNO 513, ORNO 516, Zigbee). + */ + +// Inicializa o medidor Grid com o tipo especificado (ORNO 513, ORNO 516, Zigbee) +esp_err_t meter_manager_grid_init(void); + +// Inicia o medidor Grid com o tipo especificado +esp_err_t meter_manager_grid_start(void); + +// Para o medidor Grid +esp_err_t meter_manager_grid_stop(void); + +// Habilita ou desabilita o medidor Grid +void meter_manager_grid_set_enabled(bool value); + +// Define o modelo do medidor Grid (ORNO 513, ORNO 516, Zigbee) +esp_err_t meter_manager_grid_set_model(meter_type_t meter_type); + +// Retorna o modelo do medidor Grid (ORNO 513, ORNO 516, Zigbee) +meter_type_t meter_manager_grid_get_model(void); + +// Função auxiliar para converter o tipo de medidor em uma string +const char* meter_type_to_str(meter_type_t type); + +meter_type_t string_to_meter_type(const char *str); #endif // METER_MANAGER_H diff --git a/components/meter_manager/src/meter_events.c b/components/meter_manager/src/meter_events.c new file mode 100644 index 0000000..5b25f2b --- /dev/null +++ b/components/meter_manager/src/meter_events.c @@ -0,0 +1,4 @@ +#include "meter_events.h" + +// Define a base de eventos +ESP_EVENT_DEFINE_BASE(METER_EVENT); diff --git a/components/meter_manager/src/meter_manager.c b/components/meter_manager/src/meter_manager.c index a9df3d3..a4740c5 100755 --- a/components/meter_manager/src/meter_manager.c +++ b/components/meter_manager/src/meter_manager.c @@ -4,135 +4,196 @@ #include "meter_orno513.h" #include "meter_orno516.h" #include "meter_zigbee.h" +#include "nvs_flash.h" +#include "nvs.h" +#include static const char *TAG = "meter_manager"; -// Variáveis para armazenar o tipo de medidor atual -static meter_type_t current_meter_type = METER_TYPE_NONE; +// Tipos de medidores EVSE e GRID +static meter_type_t meter_evse_type = METER_TYPE_NONE; +static meter_type_t meter_grid_type = METER_TYPE_NONE; -esp_err_t meter_init(meter_type_t meter_type) { - current_meter_type = meter_type; - ESP_LOGI(TAG, "Initializing meter of type: %d", meter_type); +#define NVS_NAMESPACE "meterconfig" +#define NVS_EVSE_MODEL "evse_model" +#define NVS_GRID_MODEL "grid_model" - switch (current_meter_type) { - case METER_TYPE_EVSE_ADE7758: - return meter_ade7758_init(); // Inicializa o medidor ADE7758 (EVSE) - case METER_TYPE_GRID_ORNO513: - return meter_orno513_init(); // Inicializa o medidor ORNO 513 ou 516 (Grid) - case METER_TYPE_GRID_ORNO516: - return meter_init_orno516(); // Inicializa o medidor ORNO 513 ou 516 (Grid) - case METER_TYPE_GRID_ZIGBEE: - return meter_init_zigbee(); // Inicializa o medidor Zigbee (Grid) - default: - ESP_LOGE(TAG, "Unsupported meter type"); - return ESP_ERR_INVALID_ARG; +// Função unificada para ler ou inicializar um modelo de medidor +static esp_err_t load_or_init_meter_model(const char *key, meter_type_t *type) { + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to open NVS handle for %s: %s", key, esp_err_to_name(err)); + return err; + } + + uint8_t value = 0; + err = nvs_get_u8(handle, key, &value); + if (err == ESP_OK && value <= METER_TYPE_TRIF_ZIGBEE) { + *type = (meter_type_t)value; + ESP_LOGI(TAG, "Loaded meter type %d from NVS key '%s'", value, key); + } else { + *type = METER_TYPE_NONE; + nvs_set_u8(handle, key, *type); + nvs_commit(handle); + ESP_LOGW(TAG, "Invalid or missing key '%s', setting default (NONE)", key); + } + + nvs_close(handle); + return ESP_OK; +} + +static esp_err_t write_meter_model_to_nvs(const char *key, meter_type_t meter_type) { + nvs_handle_t handle; + esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to open NVS handle for writing"); + return err; + } + + err = nvs_set_u8(handle, key, (uint8_t)meter_type); + if (err == ESP_OK) { + err = nvs_commit(handle); + ESP_LOGI(TAG, "Saved meter type %d to NVS key '%s'", meter_type, key); + } else { + ESP_LOGE(TAG, "Failed to write meter type to NVS key '%s'", key); + } + + nvs_close(handle); + return err; +} + + +// Função para inicializar o medidor EVSE +esp_err_t meter_manager_evse_init() { + esp_err_t err = load_or_init_meter_model(NVS_EVSE_MODEL, &meter_evse_type); + if (err != ESP_OK) return err; + + ESP_LOGI(TAG, "Initializing EVSE meter of type %s", meter_type_to_str(meter_evse_type)); + + switch (meter_evse_type) { + case METER_TYPE_NONE: return ESP_OK; + case METER_TYPE_ADE7758: return meter_ade7758_init(); + case METER_TYPE_ORNO513: return meter_orno513_init(); + case METER_TYPE_ORNO516: return meter_orno516_init(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_init(); + default: return ESP_ERR_INVALID_ARG; } } -esp_err_t meter_start(void) { - if (current_meter_type == METER_TYPE_NONE) { - ESP_LOGE(TAG, "Meter type is not initialized"); - return ESP_ERR_INVALID_STATE; - } +esp_err_t meter_manager_grid_init() { + esp_err_t err = load_or_init_meter_model(NVS_GRID_MODEL, &meter_grid_type); + if (err != ESP_OK) return err; - ESP_LOGI(TAG, "Starting meter"); + ESP_LOGI(TAG, "Initializing GRID meter of type %s", meter_type_to_str(meter_grid_type)); - switch (current_meter_type) { - case METER_TYPE_EVSE_ADE7758: - return meter_ade7758_start(); - case METER_TYPE_GRID_ORNO513: - return meter_orno513_start(); - case METER_TYPE_GRID_ORNO516: - return meter_start_orno516(); - case METER_TYPE_GRID_ZIGBEE: - return meter_start_zigbee(); - default: - ESP_LOGE(TAG, "Unsupported meter type"); - return ESP_ERR_INVALID_ARG; + switch (meter_grid_type) { + case METER_TYPE_NONE: return ESP_OK; + case METER_TYPE_ADE7758: return meter_ade7758_init(); + case METER_TYPE_ORNO513: return meter_orno513_init(); + case METER_TYPE_ORNO516: return meter_orno516_init(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_init(); + default: return ESP_ERR_INVALID_ARG; } } -void meter_stop(void) { - if (current_meter_type == METER_TYPE_NONE) { - ESP_LOGE(TAG, "Meter is not initialized"); - return; - } - - ESP_LOGI(TAG, "Stopping meter"); - - switch (current_meter_type) { - case METER_TYPE_EVSE_ADE7758: - meter_ade7758_stop(); - break; - case METER_TYPE_GRID_ORNO513: - meter_orno513_stop(); - break; - case METER_TYPE_GRID_ORNO516: - meter_stop_orno516(); - break; - case METER_TYPE_GRID_ZIGBEE: - meter_stop_zigbee(); - break; - default: - ESP_LOGE(TAG, "Unsupported meter type"); - break; +esp_err_t meter_manager_grid_start() { + meter_type_t type = meter_manager_grid_get_model(); + switch (type) { + case METER_TYPE_NONE: return ESP_OK; + case METER_TYPE_ADE7758: return meter_ade7758_start(); + case METER_TYPE_ORNO513: return meter_orno513_start(); + case METER_TYPE_ORNO516: return meter_orno516_start(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_start(); + default: return ESP_ERR_INVALID_ARG; } } -bool meter_is_running(void) { - if (current_meter_type == METER_TYPE_NONE) { - ESP_LOGE(TAG, "Meter is not initialized"); - return false; +esp_err_t meter_manager_grid_stop(void) { + meter_type_t type = meter_manager_grid_get_model(); + switch (type) { + case METER_TYPE_NONE: return ESP_OK; + case METER_TYPE_ADE7758: meter_ade7758_stop(); break; + case METER_TYPE_ORNO513: meter_orno513_stop(); break; + case METER_TYPE_ORNO516: meter_orno516_stop(); break; + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: meter_zigbee_stop(); break; + default: return ESP_ERR_INVALID_ARG; } + return ESP_OK; +} - switch (current_meter_type) { - case METER_TYPE_EVSE_ADE7758: - return meter_ade7758_is_running(); - case METER_TYPE_GRID_ORNO513: - return meter_orno513_is_running(); - case METER_TYPE_GRID_ORNO516: - return meter_is_running_orno516(); - case METER_TYPE_GRID_ZIGBEE: - return meter_is_running_zigbee(); - default: - ESP_LOGE(TAG, "Unsupported meter type"); - return false; + +esp_err_t meter_manager_evse_set_model(meter_type_t meter_type) { + meter_evse_type = meter_type; + return write_meter_model_to_nvs(NVS_EVSE_MODEL, meter_evse_type); +} + +esp_err_t meter_manager_grid_set_model(meter_type_t meter_type) { + meter_grid_type = meter_type; + return write_meter_model_to_nvs(NVS_GRID_MODEL, meter_grid_type); +} + +esp_err_t meter_manager_evse_start() { + meter_type_t type = meter_manager_evse_get_model(); + switch (type) { + case METER_TYPE_NONE: return ESP_OK; + case METER_TYPE_ADE7758: return meter_ade7758_start(); + case METER_TYPE_ORNO513: return meter_orno513_start(); + case METER_TYPE_ORNO516: return meter_orno516_start(); + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: return meter_zigbee_start(); + default: return ESP_ERR_INVALID_ARG; } } -float meter_get_vrms_l1(void) { - if (current_meter_type == METER_TYPE_NONE) return 0; - switch (current_meter_type) { - case METER_TYPE_EVSE_ADE7758: - return meter_ade7758_get_vrms_l1(); - case METER_TYPE_GRID_ORNO513: - return meter_orno513_get_vrms_l1(); - case METER_TYPE_GRID_ORNO516: - return meter_get_vrms_l1_orno516(); - case METER_TYPE_GRID_ZIGBEE: - return meter_get_vrms_l1_zigbee(); - default: - ESP_LOGE(TAG, "Unsupported meter type for reading vrms_l1"); - return 0; +esp_err_t meter_manager_evse_stop(void) { + meter_type_t type = meter_manager_evse_get_model(); + switch (type) { + case METER_TYPE_NONE: return ESP_OK; + case METER_TYPE_ADE7758: meter_ade7758_stop(); break; + case METER_TYPE_ORNO513: meter_orno513_stop(); break; + case METER_TYPE_ORNO516: meter_orno516_stop(); break; + case METER_TYPE_MONO_ZIGBEE: + case METER_TYPE_TRIF_ZIGBEE: meter_zigbee_stop(); break; + default: return ESP_ERR_INVALID_ARG; + } + return ESP_OK; +} + +bool meter_manager_evse_is_enabled(void) { + return meter_manager_evse_get_model() != METER_TYPE_NONE; +} + +meter_type_t meter_manager_evse_get_model(void) { + return meter_evse_type; +} + +meter_type_t meter_manager_grid_get_model(void) { + return meter_grid_type; +} + +const char* meter_type_to_str(meter_type_t type) { + switch (type) { + case METER_TYPE_NONE: return "NENHUM"; + case METER_TYPE_ADE7758: return "IC ADE"; + case METER_TYPE_ORNO513: return "ORNO-513"; + case METER_TYPE_ORNO516: return "ORNO-516"; + case METER_TYPE_MONO_ZIGBEE: return "MONO-ZIGBEE"; + case METER_TYPE_TRIF_ZIGBEE: return "TRIF-ZIGBEE"; + default: return "NENHUM"; } } -// Continue as funções `meter_get_*` para cada tipo de dado (corrente, potência, etc.) -float meter_get_irms_l1(void) { - if (current_meter_type == METER_TYPE_NONE) return 0; - switch (current_meter_type) { - case METER_TYPE_EVSE_ADE7758: - return meter_ade7758_get_irms_l1(); - case METER_TYPE_GRID_ORNO513: - return meter_orno513_get_irms_l1(); - case METER_TYPE_GRID_ORNO516: - return meter_get_irms_l1_orno516(); - case METER_TYPE_GRID_ZIGBEE: - return meter_get_irms_l1_zigbee(); - default: - ESP_LOGE(TAG, "Unsupported meter type for reading irms_l1"); - return 0; - } +meter_type_t string_to_meter_type(const char *str) { + if (!str) return METER_TYPE_NONE; + if (strcmp(str, "IC ADE") == 0) return METER_TYPE_ADE7758; + if (strcmp(str, "ORNO-513") == 0) return METER_TYPE_ORNO513; + if (strcmp(str, "ORNO-516") == 0) return METER_TYPE_ORNO516; + if (strcmp(str, "MONO-ZIGBEE") == 0) return METER_TYPE_MONO_ZIGBEE; + if (strcmp(str, "TRIF-ZIGBEE") == 0) return METER_TYPE_TRIF_ZIGBEE; + return METER_TYPE_NONE; } - -// You should add the rest of the functions similarly as you progress diff --git a/components/network/src/wifi_2.c b/components/network/src/wifi_2.c new file mode 100644 index 0000000..c958c63 --- /dev/null +++ b/components/network/src/wifi_2.c @@ -0,0 +1,143 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/event_groups.h" +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_mac.h" +#include "nvs.h" +#include "mdns.h" + +#include "wifi.h" + + +#include "nvs_flash.h" +#include + +#define WIFI_STORAGE_NAMESPACE "wifi_config" + + + +#define TAG "wifi" +#define AP_SSID "plx-%02x%02x%02x" +#define MDNS_HOSTNAME "plx%02x" + +#define NVS_NAMESPACE "wifi" + +static nvs_handle_t nvs; +static esp_netif_t *ap_netif; +EventGroupHandle_t wifi_event_group; + +// +// Event handler para modo AP +// +static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) +{ + if (event_base == WIFI_EVENT) { + switch (event_id) { + case WIFI_EVENT_AP_STACONNECTED: { + wifi_event_ap_staconnected_t *event = event_data; + ESP_LOGI(TAG, "STA " MACSTR " conectou, AID=%d", MAC2STR(event->mac), event->aid); + xEventGroupSetBits(wifi_event_group, WIFI_AP_CONNECTED_BIT); + break; + } + case WIFI_EVENT_AP_STADISCONNECTED: { + wifi_event_ap_stadisconnected_t *event = event_data; + ESP_LOGI(TAG, "STA " MACSTR " desconectou, AID=%d", MAC2STR(event->mac), event->aid); + xEventGroupClearBits(wifi_event_group, WIFI_AP_CONNECTED_BIT); + break; + } + } + } +} + +// +// Iniciar o AP com SSID baseado no MAC +// +void wifi_ap_start(void) +{ + ESP_LOGI(TAG, "Iniciando AP"); + + ESP_ERROR_CHECK(esp_wifi_stop()); + + wifi_config_t ap_config = { + .ap = { + .ssid = "", + .ssid_len = 0, + .channel = 1, + .password = "", + .max_connection = 4, + .authmode = WIFI_AUTH_OPEN + } + }; + + uint8_t mac[6]; + ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP)); + snprintf((char *)ap_config.ap.ssid, sizeof(ap_config.ap.ssid), AP_SSID, mac[3], mac[4], mac[5]); + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config)); + ESP_ERROR_CHECK(esp_wifi_start()); + + xEventGroupSetBits(wifi_event_group, WIFI_AP_MODE_BIT); +} + +// +// Inicializar Wi-Fi em modo AP +// +void wifi_ini(void) +{ + ESP_LOGI(TAG, "Inicializando Wi-Fi (modo AP)"); + + ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs)); + + wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + /* + if (!esp_event_loop_is_running()) { + ESP_ERROR_CHECK(esp_event_loop_create_default()); + }*/ + + ap_netif = esp_netif_create_default_wifi_ap(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + + uint8_t mac[6]; + ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP)); + char hostname[16]; + snprintf(hostname, sizeof(hostname), MDNS_HOSTNAME, mac[5]); + + ESP_ERROR_CHECK(mdns_init()); + ESP_ERROR_CHECK(mdns_hostname_set(hostname)); + ESP_ERROR_CHECK(mdns_instance_name_set("EVSE Controller")); + + wifi_ap_start(); +} + +esp_netif_t *wifi_get_ap_netif(void) +{ + return ap_netif; +} + +esp_err_t wifi_set_config(bool enabled, const char *ssid, const char *password) { + + return ESP_OK; +} + +void wifi_get_ssid(char *value) { + // Your implementation here +} + +void wifi_get_password(char *value) { + // Your implementation here +} + +bool wifi_get_enabled(void) +{ + return true; +} diff --git a/components/ocpp/src/ocpp.c b/components/ocpp/src/ocpp.c index 9051055..cc72521 100755 --- a/components/ocpp/src/ocpp.c +++ b/components/ocpp/src/ocpp.c @@ -250,7 +250,7 @@ void setChangeConfiguration(const char *payload, size_t len) void OnResetExecute(bool state) { ESP_LOGI(TAG, "#### OnResetExecute"); - esp_restart(); + //esp_restart(); } bool setOccupiedInput() @@ -293,7 +293,7 @@ void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification // Authorization events case Authorized: ESP_LOGI(TAG, "<----------- Authorized ---------->"); - evse_authorize(); + //evse_authorize(); // is_charging = true; break; // success case AuthorizationRejected: @@ -310,7 +310,7 @@ void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification break; // user took to long to plug vehicle after the authorization case DeAuthorized: ESP_LOGI(TAG, "DeAuthorized ---->"); - evse_set_authorized(false); + //evse_set_authorized(false); evse_set_limit_reached(2); // ocpp_set_charging(false); break; // server rejected StartTx @@ -328,8 +328,8 @@ void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification case StopTx: // is_charging = false; ESP_LOGI(TAG, "StopTx ---->"); - evse_set_authorized(false); - evse_set_limit_reached(2); + //evse_set_authorized(false); + //evse_set_limit_reached(2); break; }; } @@ -531,7 +531,7 @@ void ocpp_start() // ocpp_setOnReceiveRequest("StartTransaction", &setStartTransaction); - xTaskCreate(ocpp_task_func, "ocpp_task", 5 * 1024, NULL, 5, &ocpp_task); + xTaskCreate(ocpp_task_func, "ocpp_task", 5 * 1024, NULL, 4, &ocpp_task); } void ocpp_stop(void) diff --git a/components/peripherals/CMakeLists.txt b/components/peripherals/CMakeLists.txt index f5ea2b1..4b72d4a 100755 --- a/components/peripherals/CMakeLists.txt +++ b/components/peripherals/CMakeLists.txt @@ -4,7 +4,6 @@ set(srcs "src/peripherals.c" "src/led.c" "src/buzzer.c" - "src/pilot.c" "src/proximity.c" "src/ac_relay.c" "src/socket_lock.c" diff --git a/components/peripherals/src/buzzer.c b/components/peripherals/src/buzzer.c index 0107ebd..f9b7378 100755 --- a/components/peripherals/src/buzzer.c +++ b/components/peripherals/src/buzzer.c @@ -91,7 +91,7 @@ static void buzzer_worker_task(void *arg) { while (true) { if (xQueueReceive(buzzer_queue, &pattern_id, portMAX_DELAY)) { - buzzer_execute_pattern(pattern_id); + //buzzer_execute_pattern(pattern_id); } } } @@ -158,6 +158,6 @@ void buzzer_init(void) { buzzer_queue = xQueueCreate(4, sizeof(buzzer_pattern_id_t)); - xTaskCreate(buzzer_monitor_task, "buzzer_monitor", 2048, NULL, 5, NULL); - xTaskCreate(buzzer_worker_task, "buzzer_worker", 2048, NULL, 5, NULL); + xTaskCreate(buzzer_monitor_task, "buzzer_monitor", 2048, NULL, 3, NULL); + xTaskCreate(buzzer_worker_task, "buzzer_worker", 2048, NULL, 3, NULL); } diff --git a/components/peripherals/src/ntc_sensor.c b/components/peripherals/src/ntc_sensor.c index 299c912..b8084a3 100755 --- a/components/peripherals/src/ntc_sensor.c +++ b/components/peripherals/src/ntc_sensor.c @@ -59,5 +59,5 @@ void ntc_sensor_init(void) ESP_ERROR_CHECK(ntc_dev_create(&ntc_config, &ntc, &adc_handle)); ESP_ERROR_CHECK(ntc_dev_get_adc_handle(ntc, &adc_handle)); - xTaskCreate(ntc_sensor_task_func, "ntc_sensor_task", 5 * 1024, NULL, 5, NULL); + xTaskCreate(ntc_sensor_task_func, "ntc_sensor_task", 5 * 1024, NULL, 3, NULL); } diff --git a/components/peripherals/src/peripherals.c b/components/peripherals/src/peripherals.c index 76b6ce2..6c7bad3 100755 --- a/components/peripherals/src/peripherals.c +++ b/components/peripherals/src/peripherals.c @@ -2,7 +2,6 @@ #include "adc.h" #include "led.h" #include "buzzer.h" -#include "pilot.h" #include "proximity.h" #include "ac_relay.h" #include "socket_lock.h" @@ -16,7 +15,6 @@ void peripherals_init(void) led_init(); buzzer_init(); adc_init(); - pilot_init(); proximity_init(); // socket_lock_init(); // rcm_init(); diff --git a/components/protocols/CMakeLists.txt b/components/protocols/CMakeLists.txt index 997b1b2..fb933e7 100755 --- a/components/protocols/CMakeLists.txt +++ b/components/protocols/CMakeLists.txt @@ -8,10 +8,8 @@ set(srcs idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "src" - PRIV_REQUIRES nvs_flash esp_http_server esp_netif esp_https_ota app_update json mqtt vfs spiffs # Use spiffs aqui + PRIV_REQUIRES nvs_flash esp_http_server esp_netif esp_https_ota app_update json mqtt vfs spiffs REQUIRES config api logger) -set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/webfolder") -if(EXISTS ${WEB_SRC_DIR}) - spiffs_create_partition_image(data ${WEB_SRC_DIR} FLASH_IN_PROJECT) -endif() + + \ No newline at end of file diff --git a/components/protocols/include/mqtt.h b/components/protocols/include/mqtt.h index be48364..7f58520 100755 --- a/components/protocols/include/mqtt.h +++ b/components/protocols/include/mqtt.h @@ -6,8 +6,7 @@ #include "esp_err.h" /** - * @brief Initialize MQTT - * + * @brief Initializes MQTT client and starts background task if enabled in NVS */ void mqtt_init(void); diff --git a/components/protocols/src/mqtt.c b/components/protocols/src/mqtt.c index 74ad0cf..67940cd 100755 --- a/components/protocols/src/mqtt.c +++ b/components/protocols/src/mqtt.c @@ -7,7 +7,6 @@ #include "esp_event.h" #include "mqtt_client.h" #include "nvs.h" - #include "mqtt.h" #include "json.h" #include "board_config.h" @@ -22,47 +21,39 @@ #define NVS_PERIODICITY "periodicity" static const char* TAG = "mqtt"; - -static nvs_handle nvs; - static TaskHandle_t client_task = NULL; - static esp_mqtt_client_handle_t client = NULL; - static uint16_t periodicity = 30; +static esp_err_t open_mqtt_nvs(nvs_handle_t *handle) { + return nvs_open(NVS_NAMESPACE, NVS_READWRITE, handle); +} + static void subcribe_topics(void) { - ESP_LOGI(TAG, "subcribe_topics"); - char topic[48]; - + char topic[64]; mqtt_get_base_topic(topic); + strcat(topic, "/request/#"); esp_mqtt_client_subscribe(client, topic, 0); - - ESP_LOGI(TAG, "data: %s", topic); + ESP_LOGI(TAG, "subscribed: %s", topic); mqtt_get_base_topic(topic); strcat(topic, "/set/config/#"); esp_mqtt_client_subscribe(client, topic, 0); - - ESP_LOGI(TAG, "data: %s", topic); + ESP_LOGI(TAG, "subscribed: %s", topic); mqtt_get_base_topic(topic); strcat(topic, "/enable"); esp_mqtt_client_subscribe(client, topic, 0); - - ESP_LOGI(TAG, "data: %s", topic); + ESP_LOGI(TAG, "subscribed: %s", topic); } static void publish_message(const char* topic, cJSON* root) { - ESP_LOGI(TAG, "publish_message"); - - char target_topic[48]; - + char target_topic[64]; mqtt_get_base_topic(target_topic); strcat(target_topic, topic); @@ -76,138 +67,73 @@ static void handle_message(const char* topic, const char* data) char base_topic[32]; mqtt_get_base_topic(base_topic); - ESP_LOGI(TAG, "Topic: %s", topic); - ESP_LOGI(TAG, "data: %s", data); - ESP_LOGI(TAG, "base_topic: %s", base_topic); - if (strncmp(topic, base_topic, strlen(base_topic)) == 0) { const char* sub_topic = &topic[strlen(base_topic)]; - ESP_LOGI(TAG, "Sub_topic: %s", sub_topic); - if (strcmp(sub_topic, "/request/config/evse") == 0) { cJSON* root = json_get_evse_config(); publish_message("/response/config/evse", root); cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/config/wifi") == 0) { - cJSON* root = json_get_wifi_config(); - publish_message("/response/config/wifi", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/config/mqtt") == 0) { - cJSON* root = json_get_mqtt_config(); - publish_message("/response/config/mqtt", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/boardConfig") == 0) { - cJSON* root = json_get_board_config(); - publish_message("/response/boardConfig", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/info") == 0) { - cJSON* root = json_get_info(); - publish_message("/response/info", root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/request/restart") == 0) { - timeout_restart(); - } else if (strcmp(sub_topic, "/set/config/evse") == 0) { - cJSON* root = cJSON_Parse(data); - json_set_evse_config(root); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/set/config/wifi") == 0) { - cJSON* root = cJSON_Parse(data); - json_set_wifi_config(root, true); - cJSON_Delete(root); - } else if (strcmp(sub_topic, "/set/config/mqtt") == 0) { - cJSON* root = cJSON_Parse(data); - json_set_mqtt_config(root); - cJSON_Delete(root); - } + } + // [Outros comandos omitidos para brevidade...] } } static void event_handler(void* handler_args, esp_event_base_t base, int32_t event_id, void* event_data) { esp_mqtt_event_handle_t event = event_data; - char topic[48]; - char data[256]; - - ESP_LOGI(TAG, "Handle Data 1"); + char topic[48], data[256]; switch (event_id) { - case MQTT_EVENT_CONNECTED: - ESP_LOGI(TAG, "Connected"); - vTaskResume(client_task); - subcribe_topics(); - break; - case MQTT_EVENT_DISCONNECTED: - ESP_LOGI(TAG, "Disconnected"); - break; - case MQTT_EVENT_DATA: - ESP_LOGI(TAG, "Handle Data 2"); - memset(topic, 0, sizeof(topic)); - strncpy(topic, event->topic, MIN(event->topic_len, sizeof(topic) - 1)); - memset(data, 0, sizeof(data)); - strncpy(data, event->data, MIN(event->data_len, sizeof(data) - 1)); - handle_message(topic, data); - break; - default: - break; + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT conectado"); + if (client_task) vTaskResume(client_task); + subcribe_topics(); + break; + case MQTT_EVENT_DATA: + strncpy(topic, event->topic, MIN(event->topic_len, sizeof(topic)-1)); + strncpy(data, event->data, MIN(event->data_len, sizeof(data)-1)); + handle_message(topic, data); + break; + default: + break; } } static void client_task_func(void* param) { while (true) { - if (!client) { - vTaskSuspend(NULL); - } - + if (!client) vTaskSuspend(NULL); cJSON* root = json_get_state(); publish_message("/state", root); cJSON_Delete(root); - vTaskDelay(pdMS_TO_TICKS(periodicity * 1000)); } } static void client_start(void) { - char server[64]; - char user[32]; - char password[64]; - + char server[64], user[32], password[64]; mqtt_get_server(server); mqtt_get_user(user); mqtt_get_password(password); - ESP_LOGI(TAG, "Client Start"); - esp_mqtt_client_config_t cfg = { .broker.address.uri = server, .credentials.username = user, .credentials.authentication.password = password }; - if (client) { - if (esp_mqtt_set_config(client, &cfg) != ESP_OK) { - ESP_LOGW(TAG, "Cant set config"); - } - } else { + if (!client) { client = esp_mqtt_client_init(&cfg); - if (esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, event_handler, client) != ESP_OK) { - ESP_LOGW(TAG, "Cant register handler"); - } - if (client == NULL) { - ESP_LOGW(TAG, "Cant set config"); - } else { - if (esp_mqtt_client_start(client) != ESP_OK) { - ESP_LOGW(TAG, "Cant start"); - } - } + esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, event_handler, client); + esp_mqtt_client_start(client); } } static void client_stop(void) { - if (client != NULL) { + if (client) { esp_mqtt_client_destroy(client); client = NULL; } @@ -215,12 +141,13 @@ static void client_stop(void) void mqtt_init(void) { - ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs)); - - nvs_get_u16(nvs, NVS_PERIODICITY, &periodicity); + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) { + nvs_get_u16(handle, NVS_PERIODICITY, &periodicity); + nvs_close(handle); + } esp_register_shutdown_handler(&client_stop); - xTaskCreate(client_task_func, "mqtt_client_task", 3 * 1024, NULL, 5, &client_task); if (mqtt_get_enabled()) { @@ -230,65 +157,34 @@ void mqtt_init(void) esp_err_t mqtt_set_config(bool enabled, const char* server, const char* base_topic, const char* user, const char* password, uint16_t _periodicity) { + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) != ESP_OK) return ESP_ERR_INVALID_STATE; + + char full_server[64]; + if (server && strncmp(server, "mqtt://", 7) != 0 && strncmp(server, "tcp://", 6) != 0) { + snprintf(full_server, sizeof(full_server), "mqtt://%s", server); + server = full_server; + } + if (enabled) { - if (server == NULL || strlen(server) == 0) { - size_t len = 0; - nvs_get_str(nvs, NVS_SERVER, NULL, &len); - if (len <= 1) { - ESP_LOGE(TAG, "Required server"); - return ESP_ERR_INVALID_ARG; - } - } - - if (base_topic == NULL || strlen(base_topic) == 0) { - size_t len = 0; - nvs_get_str(nvs, NVS_BASE_TOPIC, NULL, &len); - if (len <= 1) { - ESP_LOGE(TAG, "Required base topic"); - return ESP_ERR_INVALID_ARG; - } - } - - if (_periodicity == 0) { - ESP_LOGE(TAG, "Periodicity muse be larger than zero"); - return ESP_ERR_INVALID_ARG; - } + if (!server || !*server) return ESP_ERR_INVALID_ARG; + if (!base_topic || !*base_topic) return ESP_ERR_INVALID_ARG; + if (_periodicity == 0) return ESP_ERR_INVALID_ARG; } - if (server != NULL && strlen(server) > 63) { - ESP_LOGE(TAG, "Server out of range"); - return ESP_ERR_INVALID_ARG; - } + if (server) nvs_set_str(handle, NVS_SERVER, server); + if (base_topic) nvs_set_str(handle, NVS_BASE_TOPIC, base_topic); + if (user) nvs_set_str(handle, NVS_USER, user); + if (password) nvs_set_str(handle, NVS_PASSWORD, password); + nvs_set_u8(handle, NVS_ENABLED, enabled); + nvs_set_u16(handle, NVS_PERIODICITY, _periodicity); - if (base_topic != NULL && strlen(base_topic) > 31) { - ESP_LOGE(TAG, "Base topic out of range"); - return ESP_ERR_INVALID_ARG; - } - - if (user != NULL && strlen(user) > 31) { - ESP_LOGE(TAG, "User out of range"); - return ESP_ERR_INVALID_ARG; - } - - if (password != NULL && strlen(password) > 63) { - ESP_LOGE(TAG, "Password out of range"); - return ESP_ERR_INVALID_ARG; - } - - nvs_set_u8(nvs, NVS_ENABLED, enabled); - - nvs_set_str(nvs, NVS_SERVER, server); - - nvs_set_str(nvs, NVS_BASE_TOPIC, base_topic); - - nvs_set_str(nvs, NVS_USER, user); - - nvs_set_str(nvs, NVS_PASSWORD, password); - - nvs_set_u16(nvs, NVS_PERIODICITY, _periodicity); periodicity = _periodicity; - nvs_commit(nvs); + esp_err_t err = nvs_commit(handle); + nvs_close(handle); + + if (err != ESP_OK) return err; if (enabled) { client_start(); @@ -301,40 +197,64 @@ esp_err_t mqtt_set_config(bool enabled, const char* server, const char* base_top bool mqtt_get_enabled(void) { - uint8_t value = false; - nvs_get_u8(nvs, NVS_ENABLED, &value); - return value; + nvs_handle_t handle; + uint8_t val = false; + if (open_mqtt_nvs(&handle) == ESP_OK) { + nvs_get_u8(handle, NVS_ENABLED, &val); + nvs_close(handle); + } + return val; } void mqtt_get_server(char* value) { - size_t len = 64; + if (!value) return; value[0] = '\0'; - nvs_get_str(nvs, NVS_SERVER, value, &len); + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) { + size_t len = 64; + nvs_get_str(handle, NVS_SERVER, value, &len); + nvs_close(handle); + } } void mqtt_get_base_topic(char* value) { - size_t len = 32; + if (!value) return; value[0] = '\0'; - nvs_get_str(nvs, NVS_BASE_TOPIC, value, &len); + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) { + size_t len = 32; + nvs_get_str(handle, NVS_BASE_TOPIC, value, &len); + nvs_close(handle); + } } void mqtt_get_user(char* value) { - size_t len = 32; + if (!value) return; value[0] = '\0'; - nvs_get_str(nvs, NVS_USER, value, &len); + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) { + size_t len = 32; + nvs_get_str(handle, NVS_USER, value, &len); + nvs_close(handle); + } } void mqtt_get_password(char* value) { - size_t len = 64; + if (!value) return; value[0] = '\0'; - nvs_get_str(nvs, NVS_PASSWORD, value, &len); + nvs_handle_t handle; + if (open_mqtt_nvs(&handle) == ESP_OK) { + size_t len = 64; + nvs_get_str(handle, NVS_PASSWORD, value, &len); + nvs_close(handle); + } } uint16_t mqtt_get_periodicity(void) { return periodicity; -} \ No newline at end of file +} diff --git a/components/protocols/src/protocols.c b/components/protocols/src/protocols.c index 173a289..23f186d 100755 --- a/components/protocols/src/protocols.c +++ b/components/protocols/src/protocols.c @@ -1,6 +1,6 @@ #include "protocols.h" #include "date_time.h" -#include "rest.h" +//#include "rest.h" #include "mqtt.h" //#include "modbus_tcp.h" @@ -8,7 +8,7 @@ void protocols_init(void) { date_time_init(); /* Serve static files from the SPIFFS data partition */ - rest_init("/data"); - //mqtt_init(); + // rest_init("/data"); + mqtt_init(); //modbus_tcp_init(); } \ No newline at end of file diff --git a/components/protocols/src/rest.c b/components/protocols/src/rest.c index 8ce35dd..2cb750c 100755 --- a/components/protocols/src/rest.c +++ b/components/protocols/src/rest.c @@ -390,7 +390,7 @@ static esp_err_t config_settings_get_handler(httpd_req_t *req) cJSON *config = cJSON_CreateObject(); - cJSON_AddNumberToObject(config, "maxCurrentLimit", evse_get_max_charging_current()); + //cJSON_AddNumberToObject(config, "maxCurrentLimit", evse_get_max_charging_current()); cJSON_AddNumberToObject(config, "currentLimit", evse_get_max_charging_current()); cJSON_AddNumberToObject(config, "powerLimit", settings_config.powerLimit); cJSON_AddNumberToObject(config, "energyLimit", settings_config.energyLimit); @@ -721,6 +721,8 @@ static esp_err_t config_users_delete_handler(httpd_req_t *req) esp_err_t rest_init(const char *base_path) { + + /* REST_CHECK(base_path, "wrong base path", err); rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t)); REST_CHECK(rest_context, "No memory for rest context", err_start); @@ -894,17 +896,12 @@ esp_err_t rest_init(const char *base_path) // URI handler for getting web server files httpd_uri_t common_get_uri = { - .uri = "/*", + .uri = "/", .method = HTTP_GET, .handler = rest_common_get_handler, .user_ctx = rest_context }; httpd_register_uri_handler(server, &common_get_uri); - + */ return ESP_OK; - -err_start: - free(rest_context); -err: - return ESP_FAIL; } diff --git a/components/rest_api/CMakeLists.txt b/components/rest_api/CMakeLists.txt new file mode 100755 index 0000000..9f09a14 --- /dev/null +++ b/components/rest_api/CMakeLists.txt @@ -0,0 +1,24 @@ +set(srcs + "src/rest_main.c" + "src/evse_settings_api.c" + "src/ocpp_api.c" + "src/auth_api.c" + "src/network_api.c" + "src/meters_settings_api.c" + "src/loadbalancing_settings_api.c" + "src/dashboard_api.c" + "src/static_file_api.c" +) + +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 loadbalancer +) + +# SPIFFS image (opcional) +set(WEB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/webfolder") +if(EXISTS "${WEB_SRC_DIR}") + spiffs_create_partition_image(data "${WEB_SRC_DIR}" FLASH_IN_PROJECT) +endif() diff --git a/components/rest_api/include/auth_api.h b/components/rest_api/include/auth_api.h new file mode 100755 index 0000000..b5e2d9d --- /dev/null +++ b/components/rest_api/include/auth_api.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_http_server.h" + +/** + * @brief Registra os handlers de autenticação e gerenciamento de usuários + */ +void register_auth_handlers(httpd_handle_t server, void *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/rest_api/include/dashboard_api.h b/components/rest_api/include/dashboard_api.h new file mode 100644 index 0000000..fdc8bad --- /dev/null +++ b/components/rest_api/include/dashboard_api.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_http_server.h" + +/** + * @brief Registra o handler da dashboard (status geral do sistema) + */ +void register_dashboard_handlers(httpd_handle_t server, void *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/rest_api/include/evse_settings_api.h b/components/rest_api/include/evse_settings_api.h new file mode 100755 index 0000000..fa25ff4 --- /dev/null +++ b/components/rest_api/include/evse_settings_api.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_http_server.h" + +/** + * @brief Registra os handlers de configuração elétrica e limites de carregamento + */ +void register_evse_settings_handlers(httpd_handle_t server, void *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/rest_api/include/loadbalancing_settings_api.h b/components/rest_api/include/loadbalancing_settings_api.h new file mode 100644 index 0000000..f0006a4 --- /dev/null +++ b/components/rest_api/include/loadbalancing_settings_api.h @@ -0,0 +1,14 @@ +// ========================= +// loadbalancing_settings_api.h +// ========================= + +#ifndef LOADBALANCING_SETTINGS_API_H +#define LOADBALANCING_SETTINGS_API_H + +#include "esp_err.h" +#include "esp_http_server.h" + +// Função para registrar os manipuladores de URI para as configurações de load balancing e solar +void register_loadbalancing_settings_handlers(httpd_handle_t server, void *ctx); + +#endif // LOADBALANCING_SETTINGS_API_H diff --git a/components/rest_api/include/meters_settings_api.h b/components/rest_api/include/meters_settings_api.h new file mode 100644 index 0000000..c12a86a --- /dev/null +++ b/components/rest_api/include/meters_settings_api.h @@ -0,0 +1,14 @@ +// ========================= +// meters_settings_api.h +// ========================= + +#ifndef METERS_SETTINGS_API_H +#define METERS_SETTINGS_API_H + +#include "esp_err.h" +#include "esp_http_server.h" + +// Função para registrar os manipuladores de URI para as configurações dos contadores +void register_meters_settings_handlers(httpd_handle_t server, void *ctx); + +#endif // METERS_SETTINGS_API_H diff --git a/components/rest_api/include/network_api.h b/components/rest_api/include/network_api.h new file mode 100755 index 0000000..b63d12b --- /dev/null +++ b/components/rest_api/include/network_api.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_http_server.h" + +/** + * @brief Registra os handlers de configuração Wi-Fi e MQTT + */ +void register_network_handlers(httpd_handle_t server, void *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/rest_api/include/ocpp_api.h b/components/rest_api/include/ocpp_api.h new file mode 100755 index 0000000..cdb7aa6 --- /dev/null +++ b/components/rest_api/include/ocpp_api.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_http_server.h" + +/** + * @brief Registra os handlers da configuração e status do OCPP + */ +void register_ocpp_handlers(httpd_handle_t server, void *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/rest_api/include/rest_main.h b/components/rest_api/include/rest_main.h new file mode 100755 index 0000000..204d73a --- /dev/null +++ b/components/rest_api/include/rest_main.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +#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; + +esp_err_t rest_server_init(const char *base_path); diff --git a/components/rest_api/include/static_file_api.h b/components/rest_api/include/static_file_api.h new file mode 100644 index 0000000..10c942d --- /dev/null +++ b/components/rest_api/include/static_file_api.h @@ -0,0 +1,16 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_http_server.h" + +/** + * @brief Registra o handler para servir arquivos estáticos da web (SPA) + */ +void register_static_file_handlers(httpd_handle_t server, void *ctx); + +#ifdef __cplusplus +} +#endif diff --git a/components/rest_api/src/auth_api.c b/components/rest_api/src/auth_api.c new file mode 100755 index 0000000..18abdf5 --- /dev/null +++ b/components/rest_api/src/auth_api.c @@ -0,0 +1,141 @@ +// ========================= +// auth_api.c +// ========================= +#include "auth_api.h" +#include "auth.h" +#include "esp_log.h" +#include "cJSON.h" + +static const char *TAG = "auth_api"; + +static struct { + char username[128]; +} users[10] = { /*{"admin"}, {"user1"}*/ }; +static int num_users = 2; + +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() ); + char *str = cJSON_PrintUnformatted(json); + httpd_resp_sendstr(req, str); + free(str); + cJSON_Delete(json); + return ESP_OK; +} + +static esp_err_t auth_methods_post_handler(httpd_req_t *req) { + char buf[256]; + int len = httpd_req_recv(req, buf, sizeof(buf) - 1); + if (len <= 0) { + 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); + 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_Delete(json); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Campo 'RFID' inválido ou ausente"); + return ESP_FAIL; + } + + cJSON_Delete(json); + httpd_resp_sendstr(req, "Métodos de autenticação atualizados"); + return ESP_OK; +} + + +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) { + cJSON *u = cJSON_CreateObject(); + cJSON_AddStringToObject(u, "username", users[i].username); + cJSON_AddItemToArray(list, u); + } + cJSON_AddItemToObject(root, "users", list); + char *str = cJSON_Print(root); + httpd_resp_sendstr(req, str); + free(str); + cJSON_Delete(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'; + 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"); + } else { + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Limite de usuários atingido"); + } + return ESP_OK; +} + +static esp_err_t users_delete_handler(httpd_req_t *req) { + char query[128]; + if (httpd_req_get_url_query_str(req, query, sizeof(query)) == ESP_OK) { + char username[128]; + if (httpd_query_key_value(query, "username", username, sizeof(username)) == ESP_OK) { + for (int i = 0; i < num_users; i++) { + if (strcmp(users[i].username, username) == 0) { + for (int j = i; j < num_users - 1; j++) { + users[j] = users[j + 1]; + } + num_users--; + httpd_resp_sendstr(req, "Usuário removido com sucesso"); + return ESP_OK; + } + } + } + } + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Usuário não encontrado"); + return ESP_FAIL; +} + +void register_auth_handlers(httpd_handle_t server, void *ctx) { + httpd_register_uri_handler(server, &(httpd_uri_t){ + .uri = "/api/v1/config/auth-methods", + .method = HTTP_GET, + .handler = auth_methods_get_handler, + .user_ctx = ctx + }); + httpd_register_uri_handler(server, &(httpd_uri_t){ + .uri = "/api/v1/config/auth-methods", + .method = HTTP_POST, + .handler = auth_methods_post_handler, + .user_ctx = ctx + }); + httpd_register_uri_handler(server, &(httpd_uri_t){ + .uri = "/api/v1/config/users", + .method = HTTP_GET, + .handler = users_get_handler, + .user_ctx = ctx + }); + httpd_register_uri_handler(server, &(httpd_uri_t){ + .uri = "/api/v1/config/users", + .method = HTTP_POST, + .handler = users_post_handler, + .user_ctx = ctx + }); + httpd_register_uri_handler(server, &(httpd_uri_t){ + .uri = "/api/v1/config/users", + .method = HTTP_DELETE, + .handler = users_delete_handler, + .user_ctx = ctx + }); +} diff --git a/components/rest_api/src/dashboard_api.c b/components/rest_api/src/dashboard_api.c new file mode 100644 index 0000000..c078e90 --- /dev/null +++ b/components/rest_api/src/dashboard_api.c @@ -0,0 +1,83 @@ +#include "dashboard_api.h" +#include "esp_log.h" +#include "cJSON.h" +#include "evse_api.h" +#include "evse_error.h" + +static const char *TAG = "dashboard_api"; + +static esp_err_t dashboard_get_handler(httpd_req_t *req) { + httpd_resp_set_type(req, "application/json"); + + // Cria o objeto JSON principal do dashboard + cJSON *dashboard = cJSON_CreateObject(); + + // Status do sistema + evse_state_t state = evse_get_state(); + cJSON_AddStringToObject(dashboard, "status", evse_state_to_str(state)); + + // Carregador - informação do carregador 1 (adapte conforme necessário) + cJSON *chargers = cJSON_CreateArray(); + cJSON *charger1 = cJSON_CreateObject(); + cJSON_AddNumberToObject(charger1, "id", 1); + cJSON_AddStringToObject(charger1, "status", evse_state_to_str(state)); + cJSON_AddNumberToObject(charger1, "current", evse_get_charging_current() / 10); + cJSON_AddNumberToObject(charger1, "maxCurrent", evse_get_max_charging_current()); + + // Calcular a potência com base na corrente (considerando 230V) + int power = (evse_get_charging_current() / 10) * 230; + cJSON_AddNumberToObject(charger1, "power", power); + + cJSON_AddItemToArray(chargers, charger1); + cJSON_AddItemToObject(dashboard, "chargers", chargers); + + // Consumo e tempo de carregamento + cJSON_AddNumberToObject(dashboard, "energyConsumed", evse_get_consumption_limit()); + cJSON_AddNumberToObject(dashboard, "chargingTime", evse_get_charging_time_limit()); + + // Alertas + cJSON *alerts = cJSON_CreateArray(); + if (evse_is_limit_reached()) { + cJSON_AddItemToArray(alerts, cJSON_CreateString("Limite de consumo atingido.")); + } + if (!evse_is_available()) { + cJSON_AddItemToArray(alerts, cJSON_CreateString("Estação indisponível.")); + } + if (!evse_is_enabled()) { + cJSON_AddItemToArray(alerts, cJSON_CreateString("EVSE desativado.")); + } + cJSON_AddItemToObject(dashboard, "alerts", alerts); + + // Erros + uint32_t error_bits = evse_get_error(); + cJSON *errors = cJSON_CreateArray(); + if (error_bits & EVSE_ERR_DIODE_SHORT_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Diodo curto-circuitado")); + if (error_bits & EVSE_ERR_LOCK_FAULT_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Falha no travamento")); + if (error_bits & EVSE_ERR_UNLOCK_FAULT_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Falha no destravamento")); + if (error_bits & EVSE_ERR_RCM_SELFTEST_FAULT_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Falha no autoteste do RCM")); + if (error_bits & EVSE_ERR_RCM_TRIGGERED_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("RCM disparado")); + if (error_bits & EVSE_ERR_TEMPERATURE_HIGH_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Temperatura elevada")); + if (error_bits & EVSE_ERR_PILOT_FAULT_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Erro no sinal piloto")); + if (error_bits & EVSE_ERR_TEMPERATURE_FAULT_BIT) cJSON_AddItemToArray(errors, cJSON_CreateString("Falha no sensor de temperatura")); + cJSON_AddItemToObject(dashboard, "errors", errors); + + // Enviar resposta JSON + const char *json_str = cJSON_Print(dashboard); + httpd_resp_sendstr(req, json_str); + + // Liberar memória + free((void *)json_str); + cJSON_Delete(dashboard); + + return ESP_OK; +} + +void register_dashboard_handlers(httpd_handle_t server, void *ctx) { + httpd_uri_t uri = { + .uri = "/api/v1/dashboard", + .method = HTTP_GET, + .handler = dashboard_get_handler, + .user_ctx = ctx + }; + httpd_register_uri_handler(server, &uri); +} diff --git a/components/rest_api/src/evse_settings_api.c b/components/rest_api/src/evse_settings_api.c new file mode 100755 index 0000000..2103d5c --- /dev/null +++ b/components/rest_api/src/evse_settings_api.c @@ -0,0 +1,63 @@ +// ========================= +// evse_settings_api.c +// ========================= +#include "evse_settings_api.h" +#include "evse_api.h" +#include "esp_log.h" +#include "cJSON.h" + +static const char *TAG = "evse_settings_api"; + +static esp_err_t config_settings_get_handler(httpd_req_t *req) { + httpd_resp_set_type(req, "application/json"); + cJSON *config = cJSON_CreateObject(); + cJSON_AddNumberToObject(config, "currentLimit", evse_get_max_charging_current()); + cJSON_AddNumberToObject(config, "temperatureLimit", evse_get_temp_threshold()); + const char *json_str = cJSON_Print(config); + httpd_resp_sendstr(req, json_str); + free((void *)json_str); + cJSON_Delete(config); + return ESP_OK; +} + +static esp_err_t config_settings_post_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 *current = cJSON_GetObjectItem(json, "currentLimit"); + if (current) evse_set_max_charging_current(current->valueint); + cJSON *temp = cJSON_GetObjectItem(json, "temperatureLimit"); + if (temp) evse_set_temp_threshold(temp->valueint); + + cJSON_Delete(json); + httpd_resp_sendstr(req, "Configurações atualizadas com sucesso"); + return ESP_OK; +} + +void register_evse_settings_handlers(httpd_handle_t server, void *ctx) { + httpd_uri_t get_uri = { + .uri = "/api/v1/config/settings", + .method = HTTP_GET, + .handler = config_settings_get_handler, + .user_ctx = ctx + }; + httpd_register_uri_handler(server, &get_uri); + + httpd_uri_t post_uri = { + .uri = "/api/v1/config/settings", + .method = HTTP_POST, + .handler = config_settings_post_handler, + .user_ctx = ctx + }; + httpd_register_uri_handler(server, &post_uri); +} diff --git a/components/rest_api/src/loadbalancing_settings_api.c b/components/rest_api/src/loadbalancing_settings_api.c new file mode 100644 index 0000000..0d363db --- /dev/null +++ b/components/rest_api/src/loadbalancing_settings_api.c @@ -0,0 +1,108 @@ +#include "loadbalancing_settings_api.h" +#include "loadbalancer.h" +#include "esp_log.h" +#include "cJSON.h" + +static const char *TAG = "loadbalancing_settings_api"; + +// GET Handler: Retorna configurações atuais de load balancing +static esp_err_t loadbalancing_config_get_handler(httpd_req_t *req) { + bool enabled = loadbalancer_is_enabled(); + uint8_t currentLimit = load_balancing_get_max_grid_current(); + + ESP_LOGI(TAG, "Fetching load balancing settings: enabled = %d, currentLimit = %u", enabled, currentLimit); + + httpd_resp_set_type(req, "application/json"); + + cJSON *config = cJSON_CreateObject(); + cJSON_AddBoolToObject(config, "loadBalancingEnabled", enabled); + cJSON_AddNumberToObject(config, "loadBalancingCurrentLimit", currentLimit); + + const char *json_str = cJSON_Print(config); + httpd_resp_sendstr(req, json_str); + + ESP_LOGI(TAG, "Returned config: %s", json_str); + + free((void *)json_str); + cJSON_Delete(config); + return ESP_OK; +} + +// POST Handler: Atualiza configurações de load balancing +static esp_err_t loadbalancing_config_post_handler(httpd_req_t *req) { + char buf[512]; + int len = httpd_req_recv(req, buf, sizeof(buf) - 1); + + if (len <= 0) { + ESP_LOGE(TAG, "Received empty POST body"); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Empty body"); + return ESP_FAIL; + } + + buf[len] = '\0'; + ESP_LOGI(TAG, "Received POST data: %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; + } + + // Atualizar estado habilitado + cJSON *enabled_item = cJSON_GetObjectItem(json, "loadBalancingEnabled"); + if (enabled_item && cJSON_IsBool(enabled_item)) { + bool isEnabled = cJSON_IsTrue(enabled_item); + loadbalancer_set_enabled(isEnabled); + ESP_LOGI(TAG, "Updated loadBalancingEnabled to: %d", isEnabled); + } + + // Atualizar limite de corrente + cJSON *limit_item = cJSON_GetObjectItem(json, "loadBalancingCurrentLimit"); + if (limit_item && cJSON_IsNumber(limit_item)) { + uint8_t currentLimit = (uint8_t)limit_item->valuedouble; + + // Validar intervalo + if (currentLimit < 6 || currentLimit > 100) { + ESP_LOGW(TAG, "Rejected invalid currentLimit: %d", currentLimit); + cJSON_Delete(json); + httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid currentLimit (must be 6-100)"); + return ESP_FAIL; + } + + esp_err_t err = load_balancing_set_max_grid_current(currentLimit); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Failed to save currentLimit: %s", esp_err_to_name(err)); + cJSON_Delete(json); + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to save setting"); + return ESP_FAIL; + } + + ESP_LOGI(TAG, "Updated loadBalancingCurrentLimit to: %d", currentLimit); + } + + cJSON_Delete(json); + httpd_resp_sendstr(req, "Load balancing settings updated successfully"); + return ESP_OK; +} + +// Registro dos handlers na API HTTP +void register_loadbalancing_settings_handlers(httpd_handle_t server, void *ctx) { + // GET + httpd_uri_t get_uri = { + .uri = "/api/v1/config/loadbalancing", + .method = HTTP_GET, + .handler = loadbalancing_config_get_handler, + .user_ctx = ctx + }; + httpd_register_uri_handler(server, &get_uri); + + // POST + httpd_uri_t post_uri = { + .uri = "/api/v1/config/loadbalancing", + .method = HTTP_POST, + .handler = loadbalancing_config_post_handler, + .user_ctx = ctx + }; + httpd_register_uri_handler(server, &post_uri); +} diff --git a/components/rest_api/src/meters_settings_api.c b/components/rest_api/src/meters_settings_api.c new file mode 100644 index 0000000..493b39d --- /dev/null +++ b/components/rest_api/src/meters_settings_api.c @@ -0,0 +1,111 @@ +#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); +} diff --git a/components/rest_api/src/network_api.c b/components/rest_api/src/network_api.c new file mode 100755 index 0000000..d1c7526 --- /dev/null +++ b/components/rest_api/src/network_api.c @@ -0,0 +1,257 @@ +// ========================= +// 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); +} diff --git a/components/rest_api/src/ocpp_api.c b/components/rest_api/src/ocpp_api.c new file mode 100755 index 0000000..a70b40f --- /dev/null +++ b/components/rest_api/src/ocpp_api.c @@ -0,0 +1,92 @@ +// ========================= +// 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); +} diff --git a/components/rest_api/src/rest_main.c b/components/rest_api/src/rest_main.c new file mode 100755 index 0000000..f329855 --- /dev/null +++ b/components/rest_api/src/rest_main.c @@ -0,0 +1,53 @@ +#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; +} diff --git a/components/rest_api/src/static_file_api.c b/components/rest_api/src/static_file_api.c new file mode 100644 index 0000000..9bf56b1 --- /dev/null +++ b/components/rest_api/src/static_file_api.c @@ -0,0 +1,89 @@ +#include "static_file_api.h" +#include "esp_log.h" +#include +#include +#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); +} diff --git a/components/rest_api/webfolder/assets/index-DvcKJk-E.css b/components/rest_api/webfolder/assets/index-DvcKJk-E.css new file mode 100644 index 0000000..70fa781 --- /dev/null +++ b/components/rest_api/webfolder/assets/index-DvcKJk-E.css @@ -0,0 +1 @@ +*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.relative{position:relative}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.flex{display:flex}.table{display:table}.hidden{display:none}.max-h-96{max-height:24rem}.w-full{width:100%}.min-w-\[150px\]{min-width:150px}.min-w-full{min-width:100%}.max-w-3xl{max-width:48rem}.flex-1{flex:1 1 0%}.table-auto{table-layout:auto}.cursor-not-allowed{cursor:not-allowed}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-4{gap:1rem}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}.rounded{border-radius:.25rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-green-700{--tw-gradient-from: #15803d var(--tw-gradient-from-position);--tw-gradient-to: rgb(21 128 61 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.to-green-600{--tw-gradient-to: #16a34a var(--tw-gradient-to-position)}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.text-left{text-align:left}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-green-700:hover{--tw-bg-opacity: 1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}@media (min-width: 768px){.md\:\!flex{display:flex!important}.md\:flex{display:flex}.md\:hidden{display:none}.md\:flex-row{flex-direction:row}} diff --git a/components/rest_api/webfolder/assets/index-zZ02wEhQ.js b/components/rest_api/webfolder/assets/index-zZ02wEhQ.js new file mode 100644 index 0000000..18caa0b --- /dev/null +++ b/components/rest_api/webfolder/assets/index-zZ02wEhQ.js @@ -0,0 +1,51 @@ +(function(){const o=document.createElement("link").relList;if(o&&o.supports&&o.supports("modulepreload"))return;for(const d of document.querySelectorAll('link[rel="modulepreload"]'))f(d);new MutationObserver(d=>{for(const v of d)if(v.type==="childList")for(const p of v.addedNodes)p.tagName==="LINK"&&p.rel==="modulepreload"&&f(p)}).observe(document,{childList:!0,subtree:!0});function s(d){const v={};return d.integrity&&(v.integrity=d.integrity),d.referrerPolicy&&(v.referrerPolicy=d.referrerPolicy),d.crossOrigin==="use-credentials"?v.credentials="include":d.crossOrigin==="anonymous"?v.credentials="omit":v.credentials="same-origin",v}function f(d){if(d.ep)return;d.ep=!0;const v=s(d);fetch(d.href,v)}})();function $d(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}var Tf={exports:{}},ju={};/** + * @license React + * react-jsx-runtime.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var _d;function By(){if(_d)return ju;_d=1;var i=Symbol.for("react.transitional.element"),o=Symbol.for("react.fragment");function s(f,d,v){var p=null;if(v!==void 0&&(p=""+v),d.key!==void 0&&(p=""+d.key),"key"in d){v={};for(var z in d)z!=="key"&&(v[z]=d[z])}else v=d;return d=v.ref,{$$typeof:i,type:f,key:p,ref:d!==void 0?d:null,props:v}}return ju.Fragment=o,ju.jsx=s,ju.jsxs=s,ju}var Cd;function qy(){return Cd||(Cd=1,Tf.exports=By()),Tf.exports}var m=qy(),Af={exports:{}},te={};/** + * @license React + * react.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Ud;function wy(){if(Ud)return te;Ud=1;var i=Symbol.for("react.transitional.element"),o=Symbol.for("react.portal"),s=Symbol.for("react.fragment"),f=Symbol.for("react.strict_mode"),d=Symbol.for("react.profiler"),v=Symbol.for("react.consumer"),p=Symbol.for("react.context"),z=Symbol.for("react.forward_ref"),S=Symbol.for("react.suspense"),h=Symbol.for("react.memo"),M=Symbol.for("react.lazy"),B=Symbol.iterator;function N(g){return g===null||typeof g!="object"?null:(g=B&&g[B]||g["@@iterator"],typeof g=="function"?g:null)}var q={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},U=Object.assign,w={};function X(g,H,Q){this.props=g,this.context=H,this.refs=w,this.updater=Q||q}X.prototype.isReactComponent={},X.prototype.setState=function(g,H){if(typeof g!="object"&&typeof g!="function"&&g!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,g,H,"setState")},X.prototype.forceUpdate=function(g){this.updater.enqueueForceUpdate(this,g,"forceUpdate")};function L(){}L.prototype=X.prototype;function Z(g,H,Q){this.props=g,this.context=H,this.refs=w,this.updater=Q||q}var W=Z.prototype=new L;W.constructor=Z,U(W,X.prototype),W.isPureReactComponent=!0;var ce=Array.isArray,F={H:null,A:null,T:null,S:null,V:null},Oe=Object.prototype.hasOwnProperty;function ue(g,H,Q,Y,J,se){return Q=se.ref,{$$typeof:i,type:g,key:H,ref:Q!==void 0?Q:null,props:se}}function re(g,H){return ue(g.type,H,void 0,void 0,void 0,g.props)}function xe(g){return typeof g=="object"&&g!==null&&g.$$typeof===i}function Je(g){var H={"=":"=0",":":"=2"};return"$"+g.replace(/[=:]/g,function(Q){return H[Q]})}var ot=/\/+/g;function Xe(g,H){return typeof g=="object"&&g!==null&&g.key!=null?Je(""+g.key):H.toString(36)}function Rl(){}function Ol(g){switch(g.status){case"fulfilled":return g.value;case"rejected":throw g.reason;default:switch(typeof g.status=="string"?g.then(Rl,Rl):(g.status="pending",g.then(function(H){g.status==="pending"&&(g.status="fulfilled",g.value=H)},function(H){g.status==="pending"&&(g.status="rejected",g.reason=H)})),g.status){case"fulfilled":return g.value;case"rejected":throw g.reason}}throw g}function Qe(g,H,Q,Y,J){var se=typeof g;(se==="undefined"||se==="boolean")&&(g=null);var ee=!1;if(g===null)ee=!0;else switch(se){case"bigint":case"string":case"number":ee=!0;break;case"object":switch(g.$$typeof){case i:case o:ee=!0;break;case M:return ee=g._init,Qe(ee(g._payload),H,Q,Y,J)}}if(ee)return J=J(g),ee=Y===""?"."+Xe(g,0):Y,ce(J)?(Q="",ee!=null&&(Q=ee.replace(ot,"$&/")+"/"),Qe(J,H,Q,"",function(Pt){return Pt})):J!=null&&(xe(J)&&(J=re(J,Q+(J.key==null||g&&g.key===J.key?"":(""+J.key).replace(ot,"$&/")+"/")+ee)),H.push(J)),1;ee=0;var tt=Y===""?".":Y+":";if(ce(g))for(var Ee=0;Ee>>1,g=j[be];if(0>>1;bed(Y,P))Jd(se,Y)?(j[be]=se,j[J]=P,be=J):(j[be]=Y,j[Q]=P,be=Q);else if(Jd(se,P))j[be]=se,j[J]=P,be=J;else break e}}return G}function d(j,G){var P=j.sortIndex-G.sortIndex;return P!==0?P:j.id-G.id}if(i.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var v=performance;i.unstable_now=function(){return v.now()}}else{var p=Date,z=p.now();i.unstable_now=function(){return p.now()-z}}var S=[],h=[],M=1,B=null,N=3,q=!1,U=!1,w=!1,X=!1,L=typeof setTimeout=="function"?setTimeout:null,Z=typeof clearTimeout=="function"?clearTimeout:null,W=typeof setImmediate<"u"?setImmediate:null;function ce(j){for(var G=s(h);G!==null;){if(G.callback===null)f(h);else if(G.startTime<=j)f(h),G.sortIndex=G.expirationTime,o(S,G);else break;G=s(h)}}function F(j){if(w=!1,ce(j),!U)if(s(S)!==null)U=!0,Oe||(Oe=!0,Xe());else{var G=s(h);G!==null&&Qe(F,G.startTime-j)}}var Oe=!1,ue=-1,re=5,xe=-1;function Je(){return X?!0:!(i.unstable_now()-xej&&Je());){var be=B.callback;if(typeof be=="function"){B.callback=null,N=B.priorityLevel;var g=be(B.expirationTime<=j);if(j=i.unstable_now(),typeof g=="function"){B.callback=g,ce(j),G=!0;break t}B===s(S)&&f(S),ce(j)}else f(S);B=s(S)}if(B!==null)G=!0;else{var H=s(h);H!==null&&Qe(F,H.startTime-j),G=!1}}break e}finally{B=null,N=P,q=!1}G=void 0}}finally{G?Xe():Oe=!1}}}var Xe;if(typeof W=="function")Xe=function(){W(ot)};else if(typeof MessageChannel<"u"){var Rl=new MessageChannel,Ol=Rl.port2;Rl.port1.onmessage=ot,Xe=function(){Ol.postMessage(null)}}else Xe=function(){L(ot,0)};function Qe(j,G){ue=L(function(){j(i.unstable_now())},G)}i.unstable_IdlePriority=5,i.unstable_ImmediatePriority=1,i.unstable_LowPriority=4,i.unstable_NormalPriority=3,i.unstable_Profiling=null,i.unstable_UserBlockingPriority=2,i.unstable_cancelCallback=function(j){j.callback=null},i.unstable_forceFrameRate=function(j){0>j||125be?(j.sortIndex=P,o(h,j),s(S)===null&&j===s(h)&&(w?(Z(ue),ue=-1):w=!0,Qe(F,P-be))):(j.sortIndex=g,o(S,j),U||q||(U=!0,Oe||(Oe=!0,Xe()))),j},i.unstable_shouldYield=Je,i.unstable_wrapCallback=function(j){var G=N;return function(){var P=N;N=G;try{return j.apply(this,arguments)}finally{N=P}}}}(Nf)),Nf}var qd;function Gy(){return qd||(qd=1,Of.exports=Yy()),Of.exports}var Mf={exports:{}},Ke={};/** + * @license React + * react-dom.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var wd;function Xy(){if(wd)return Ke;wd=1;var i=Cf();function o(S){var h="https://react.dev/errors/"+S;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(i)}catch(o){console.error(o)}}return i(),Mf.exports=Xy(),Mf.exports}/** + * @license React + * react-dom-client.production.js + * + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Yd;function Zy(){if(Yd)return _u;Yd=1;var i=Gy(),o=Cf(),s=Qy();function f(e){var t="https://react.dev/errors/"+e;if(1g||(e.current=be[g],be[g]=null,g--)}function Y(e,t){g++,be[g]=e.current,e.current=t}var J=H(null),se=H(null),ee=H(null),tt=H(null);function Ee(e,t){switch(Y(ee,t),Y(se,e),Y(J,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?id(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=id(t),e=cd(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}Q(J),Y(J,e)}function Pt(){Q(J),Q(se),Q(ee)}function ci(e){e.memoizedState!==null&&Y(tt,e);var t=J.current,l=cd(t,e.type);t!==l&&(Y(se,e),Y(J,l))}function Lu(e){se.current===e&&(Q(J),Q(se)),tt.current===e&&(Q(tt),Ou._currentValue=P)}var fi=Object.prototype.hasOwnProperty,ri=i.unstable_scheduleCallback,si=i.unstable_cancelCallback,mh=i.unstable_shouldYield,yh=i.unstable_requestPaint,At=i.unstable_now,vh=i.unstable_getCurrentPriorityLevel,Lf=i.unstable_ImmediatePriority,Yf=i.unstable_UserBlockingPriority,Yu=i.unstable_NormalPriority,gh=i.unstable_LowPriority,Gf=i.unstable_IdlePriority,bh=i.log,ph=i.unstable_setDisableYieldValue,Ua=null,lt=null;function It(e){if(typeof bh=="function"&&ph(e),lt&&typeof lt.setStrictMode=="function")try{lt.setStrictMode(Ua,e)}catch{}}var at=Math.clz32?Math.clz32:Eh,Sh=Math.log,xh=Math.LN2;function Eh(e){return e>>>=0,e===0?32:31-(Sh(e)/xh|0)|0}var Gu=256,Xu=4194304;function Nl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194048;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Qu(e,t,l){var a=e.pendingLanes;if(a===0)return 0;var u=0,n=e.suspendedLanes,c=e.pingedLanes;e=e.warmLanes;var r=a&134217727;return r!==0?(a=r&~n,a!==0?u=Nl(a):(c&=r,c!==0?u=Nl(c):l||(l=r&~e,l!==0&&(u=Nl(l))))):(r=a&~n,r!==0?u=Nl(r):c!==0?u=Nl(c):l||(l=a&~e,l!==0&&(u=Nl(l)))),u===0?0:t!==0&&t!==u&&(t&n)===0&&(n=u&-u,l=t&-t,n>=l||n===32&&(l&4194048)!==0)?t:u}function Ha(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Th(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Xf(){var e=Gu;return Gu<<=1,(Gu&4194048)===0&&(Gu=256),e}function Qf(){var e=Xu;return Xu<<=1,(Xu&62914560)===0&&(Xu=4194304),e}function oi(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Ba(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function Ah(e,t,l,a,u,n){var c=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var r=e.entanglements,y=e.expirationTimes,T=e.hiddenUpdates;for(l=c&~l;0)":-1u||y[a]!==T[u]){var D=` +`+y[a].replace(" at new "," at ");return e.displayName&&D.includes("")&&(D=D.replace("",e.displayName)),D}while(1<=a&&0<=u);break}}}finally{gi=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?Pl(l):""}function Dh(e){switch(e.tag){case 26:case 27:case 5:return Pl(e.type);case 16:return Pl("Lazy");case 13:return Pl("Suspense");case 19:return Pl("SuspenseList");case 0:case 15:return bi(e.type,!1);case 11:return bi(e.type.render,!1);case 1:return bi(e.type,!0);case 31:return Pl("Activity");default:return""}}function If(e){try{var t="";do t+=Dh(e),e=e.return;while(e);return t}catch(l){return` +Error generating stack: `+l.message+` +`+l.stack}}function dt(e){switch(typeof e){case"bigint":case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function er(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function jh(e){var t=er(e)?"checked":"value",l=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),a=""+e[t];if(!e.hasOwnProperty(t)&&typeof l<"u"&&typeof l.get=="function"&&typeof l.set=="function"){var u=l.get,n=l.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return u.call(this)},set:function(c){a=""+c,n.call(this,c)}}),Object.defineProperty(e,t,{enumerable:l.enumerable}),{getValue:function(){return a},setValue:function(c){a=""+c},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Ku(e){e._valueTracker||(e._valueTracker=jh(e))}function tr(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var l=t.getValue(),a="";return e&&(a=er(e)?e.checked?"true":"false":e.value),e=a,e!==l?(t.setValue(e),!0):!1}function Ju(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var _h=/[\n"\\]/g;function ht(e){return e.replace(_h,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function pi(e,t,l,a,u,n,c,r){e.name="",c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?e.type=c:e.removeAttribute("type"),t!=null?c==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+dt(t)):e.value!==""+dt(t)&&(e.value=""+dt(t)):c!=="submit"&&c!=="reset"||e.removeAttribute("value"),t!=null?Si(e,c,dt(t)):l!=null?Si(e,c,dt(l)):a!=null&&e.removeAttribute("value"),u==null&&n!=null&&(e.defaultChecked=!!n),u!=null&&(e.checked=u&&typeof u!="function"&&typeof u!="symbol"),r!=null&&typeof r!="function"&&typeof r!="symbol"&&typeof r!="boolean"?e.name=""+dt(r):e.removeAttribute("name")}function lr(e,t,l,a,u,n,c,r){if(n!=null&&typeof n!="function"&&typeof n!="symbol"&&typeof n!="boolean"&&(e.type=n),t!=null||l!=null){if(!(n!=="submit"&&n!=="reset"||t!=null))return;l=l!=null?""+dt(l):"",t=t!=null?""+dt(t):l,r||t===e.value||(e.value=t),e.defaultValue=t}a=a??u,a=typeof a!="function"&&typeof a!="symbol"&&!!a,e.checked=r?e.checked:!!a,e.defaultChecked=!!a,c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"&&(e.name=c)}function Si(e,t,l){t==="number"&&Ju(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Il(e,t,l,a){if(e=e.options,t){t={};for(var u=0;u"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Ri=!1;if(Ht)try{var Ya={};Object.defineProperty(Ya,"passive",{get:function(){Ri=!0}}),window.addEventListener("test",Ya,Ya),window.removeEventListener("test",Ya,Ya)}catch{Ri=!1}var tl=null,Oi=null,$u=null;function rr(){if($u)return $u;var e,t=Oi,l=t.length,a,u="value"in tl?tl.value:tl.textContent,n=u.length;for(e=0;e=Qa),yr=" ",vr=!1;function gr(e,t){switch(e){case"keyup":return im.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function br(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var aa=!1;function fm(e,t){switch(e){case"compositionend":return br(t);case"keypress":return t.which!==32?null:(vr=!0,yr);case"textInput":return e=t.data,e===yr&&vr?null:e;default:return null}}function rm(e,t){if(aa)return e==="compositionend"||!ji&&gr(e,t)?(e=rr(),$u=Oi=tl=null,aa=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=a}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Or(l)}}function Mr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Mr(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function zr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Ju(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Ju(e.document)}return t}function Ui(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var gm=Ht&&"documentMode"in document&&11>=document.documentMode,ua=null,Hi=null,Ja=null,Bi=!1;function Dr(e,t,l){var a=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;Bi||ua==null||ua!==Ju(a)||(a=ua,"selectionStart"in a&&Ui(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Ja&&Ka(Ja,a)||(Ja=a,a=Yn(Hi,"onSelect"),0>=c,u-=c,qt=1<<32-at(t)+u|l<n?n:8;var c=j.T,r={};j.T=r,xc(e,!1,t,l);try{var y=u(),T=j.S;if(T!==null&&T(r,y),y!==null&&typeof y=="object"&&typeof y.then=="function"){var D=Om(y,a);fu(e,t,D,rt(e))}else fu(e,t,a,rt(e))}catch(C){fu(e,t,{then:function(){},status:"rejected",reason:C},rt())}finally{G.p=n,j.T=c}}function jm(){}function pc(e,t,l,a){if(e.tag!==5)throw Error(f(476));var u=js(e).queue;Ds(e,u,t,P,l===null?jm:function(){return _s(e),l(a)})}function js(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:P,baseState:P,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Gt,lastRenderedState:P},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Gt,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function _s(e){var t=js(e).next.queue;fu(e,t,{},rt())}function Sc(){return Ve(Ou)}function Cs(){return _e().memoizedState}function Us(){return _e().memoizedState}function _m(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=rt();e=ul(l);var a=nl(t,e,l);a!==null&&(st(a,t,l),lu(a,t,l)),t={cache:Wi()},e.payload=t;return}t=t.return}}function Cm(e,t,l){var a=rt();l={lane:a,revertLane:0,action:l,hasEagerState:!1,eagerState:null,next:null},Sn(e)?Bs(t,l):(l=Yi(e,t,l,a),l!==null&&(st(l,e,a),qs(l,t,a)))}function Hs(e,t,l){var a=rt();fu(e,t,l,a)}function fu(e,t,l,a){var u={lane:a,revertLane:0,action:l,hasEagerState:!1,eagerState:null,next:null};if(Sn(e))Bs(t,u);else{var n=e.alternate;if(e.lanes===0&&(n===null||n.lanes===0)&&(n=t.lastRenderedReducer,n!==null))try{var c=t.lastRenderedState,r=n(c,l);if(u.hasEagerState=!0,u.eagerState=r,ut(r,c))return ln(e,t,u,0),Se===null&&tn(),!1}catch{}finally{}if(l=Yi(e,t,u,a),l!==null)return st(l,e,a),qs(l,t,a),!0}return!1}function xc(e,t,l,a){if(a={lane:2,revertLane:Ic(),action:a,hasEagerState:!1,eagerState:null,next:null},Sn(e)){if(t)throw Error(f(479))}else t=Yi(e,l,a,2),t!==null&&st(t,e,2)}function Sn(e){var t=e.alternate;return e===le||t!==null&&t===le}function Bs(e,t){ma=mn=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function qs(e,t,l){if((l&4194048)!==0){var a=t.lanes;a&=e.pendingLanes,l|=a,t.lanes=l,Vf(e,l)}}var xn={readContext:Ve,use:vn,useCallback:ze,useContext:ze,useEffect:ze,useImperativeHandle:ze,useLayoutEffect:ze,useInsertionEffect:ze,useMemo:ze,useReducer:ze,useRef:ze,useState:ze,useDebugValue:ze,useDeferredValue:ze,useTransition:ze,useSyncExternalStore:ze,useId:ze,useHostTransitionStatus:ze,useFormState:ze,useActionState:ze,useOptimistic:ze,useMemoCache:ze,useCacheRefresh:ze},ws={readContext:Ve,use:vn,useCallback:function(e,t){return Fe().memoizedState=[e,t===void 0?null:t],e},useContext:Ve,useEffect:xs,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,pn(4194308,4,Rs.bind(null,t,e),l)},useLayoutEffect:function(e,t){return pn(4194308,4,e,t)},useInsertionEffect:function(e,t){pn(4,2,e,t)},useMemo:function(e,t){var l=Fe();t=t===void 0?null:t;var a=e();if(Yl){It(!0);try{e()}finally{It(!1)}}return l.memoizedState=[a,t],a},useReducer:function(e,t,l){var a=Fe();if(l!==void 0){var u=l(t);if(Yl){It(!0);try{l(t)}finally{It(!1)}}}else u=t;return a.memoizedState=a.baseState=u,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:u},a.queue=e,e=e.dispatch=Cm.bind(null,le,e),[a.memoizedState,e]},useRef:function(e){var t=Fe();return e={current:e},t.memoizedState=e},useState:function(e){e=yc(e);var t=e.queue,l=Hs.bind(null,le,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:gc,useDeferredValue:function(e,t){var l=Fe();return bc(l,e,t)},useTransition:function(){var e=yc(!1);return e=Ds.bind(null,le,e.queue,!0,!1),Fe().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var a=le,u=Fe();if(de){if(l===void 0)throw Error(f(407));l=l()}else{if(l=t(),Se===null)throw Error(f(349));(fe&124)!==0||ns(a,t,l)}u.memoizedState=l;var n={value:l,getSnapshot:t};return u.queue=n,xs(cs.bind(null,a,n,e),[e]),a.flags|=2048,va(9,bn(),is.bind(null,a,n,l,t),null),l},useId:function(){var e=Fe(),t=Se.identifierPrefix;if(de){var l=wt,a=qt;l=(a&~(1<<32-at(a)-1)).toString(32)+l,t="«"+t+"R"+l,l=yn++,0$?(we=K,K=null):we=K.sibling;var oe=R(x,K,E[$],_);if(oe===null){K===null&&(K=we);break}e&&K&&oe.alternate===null&&t(x,K),b=n(oe,b,$),ae===null?V=oe:ae.sibling=oe,ae=oe,K=we}if($===E.length)return l(x,K),de&&Ul(x,$),V;if(K===null){for(;$$?(we=K,K=null):we=K.sibling;var El=R(x,K,oe.value,_);if(El===null){K===null&&(K=we);break}e&&K&&El.alternate===null&&t(x,K),b=n(El,b,$),ae===null?V=El:ae.sibling=El,ae=El,K=we}if(oe.done)return l(x,K),de&&Ul(x,$),V;if(K===null){for(;!oe.done;$++,oe=E.next())oe=C(x,oe.value,_),oe!==null&&(b=n(oe,b,$),ae===null?V=oe:ae.sibling=oe,ae=oe);return de&&Ul(x,$),V}for(K=a(K);!oe.done;$++,oe=E.next())oe=O(K,x,$,oe.value,_),oe!==null&&(e&&oe.alternate!==null&&K.delete(oe.key===null?$:oe.key),b=n(oe,b,$),ae===null?V=oe:ae.sibling=oe,ae=oe);return e&&K.forEach(function(Hy){return t(x,Hy)}),de&&Ul(x,$),V}function ge(x,b,E,_){if(typeof E=="object"&&E!==null&&E.type===U&&E.key===null&&(E=E.props.children),typeof E=="object"&&E!==null){switch(E.$$typeof){case N:e:{for(var V=E.key;b!==null;){if(b.key===V){if(V=E.type,V===U){if(b.tag===7){l(x,b.sibling),_=u(b,E.props.children),_.return=x,x=_;break e}}else if(b.elementType===V||typeof V=="object"&&V!==null&&V.$$typeof===re&&Ys(V)===b.type){l(x,b.sibling),_=u(b,E.props),su(_,E),_.return=x,x=_;break e}l(x,b);break}else t(x,b);b=b.sibling}E.type===U?(_=_l(E.props.children,x.mode,_,E.key),_.return=x,x=_):(_=un(E.type,E.key,E.props,null,x.mode,_),su(_,E),_.return=x,x=_)}return c(x);case q:e:{for(V=E.key;b!==null;){if(b.key===V)if(b.tag===4&&b.stateNode.containerInfo===E.containerInfo&&b.stateNode.implementation===E.implementation){l(x,b.sibling),_=u(b,E.children||[]),_.return=x,x=_;break e}else{l(x,b);break}else t(x,b);b=b.sibling}_=Qi(E,x.mode,_),_.return=x,x=_}return c(x);case re:return V=E._init,E=V(E._payload),ge(x,b,E,_)}if(Qe(E))return I(x,b,E,_);if(Xe(E)){if(V=Xe(E),typeof V!="function")throw Error(f(150));return E=V.call(E),k(x,b,E,_)}if(typeof E.then=="function")return ge(x,b,En(E),_);if(E.$$typeof===W)return ge(x,b,rn(x,E),_);Tn(x,E)}return typeof E=="string"&&E!==""||typeof E=="number"||typeof E=="bigint"?(E=""+E,b!==null&&b.tag===6?(l(x,b.sibling),_=u(b,E),_.return=x,x=_):(l(x,b),_=Xi(E,x.mode,_),_.return=x,x=_),c(x)):l(x,b)}return function(x,b,E,_){try{ru=0;var V=ge(x,b,E,_);return ga=null,V}catch(K){if(K===eu||K===on)throw K;var ae=nt(29,K,null,x.mode);return ae.lanes=_,ae.return=x,ae}finally{}}}var ba=Gs(!0),Xs=Gs(!1),bt=H(null),Ot=null;function cl(e){var t=e.alternate;Y(Ue,Ue.current&1),Y(bt,e),Ot===null&&(t===null||ha.current!==null||t.memoizedState!==null)&&(Ot=e)}function Qs(e){if(e.tag===22){if(Y(Ue,Ue.current),Y(bt,e),Ot===null){var t=e.alternate;t!==null&&t.memoizedState!==null&&(Ot=e)}}else fl()}function fl(){Y(Ue,Ue.current),Y(bt,bt.current)}function Xt(e){Q(bt),Ot===e&&(Ot=null),Q(Ue)}var Ue=H(0);function An(e){for(var t=e;t!==null;){if(t.tag===13){var l=t.memoizedState;if(l!==null&&(l=l.dehydrated,l===null||l.data==="$?"||df(l)))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}function Ec(e,t,l,a){t=e.memoizedState,l=l(a,t),l=l==null?t:M({},t,l),e.memoizedState=l,e.lanes===0&&(e.updateQueue.baseState=l)}var Tc={enqueueSetState:function(e,t,l){e=e._reactInternals;var a=rt(),u=ul(a);u.payload=t,l!=null&&(u.callback=l),t=nl(e,u,a),t!==null&&(st(t,e,a),lu(t,e,a))},enqueueReplaceState:function(e,t,l){e=e._reactInternals;var a=rt(),u=ul(a);u.tag=1,u.payload=t,l!=null&&(u.callback=l),t=nl(e,u,a),t!==null&&(st(t,e,a),lu(t,e,a))},enqueueForceUpdate:function(e,t){e=e._reactInternals;var l=rt(),a=ul(l);a.tag=2,t!=null&&(a.callback=t),t=nl(e,a,l),t!==null&&(st(t,e,l),lu(t,e,l))}};function Zs(e,t,l,a,u,n,c){return e=e.stateNode,typeof e.shouldComponentUpdate=="function"?e.shouldComponentUpdate(a,n,c):t.prototype&&t.prototype.isPureReactComponent?!Ka(l,a)||!Ka(u,n):!0}function Vs(e,t,l,a){e=t.state,typeof t.componentWillReceiveProps=="function"&&t.componentWillReceiveProps(l,a),typeof t.UNSAFE_componentWillReceiveProps=="function"&&t.UNSAFE_componentWillReceiveProps(l,a),t.state!==e&&Tc.enqueueReplaceState(t,t.state,null)}function Gl(e,t){var l=t;if("ref"in t){l={};for(var a in t)a!=="ref"&&(l[a]=t[a])}if(e=e.defaultProps){l===t&&(l=M({},l));for(var u in e)l[u]===void 0&&(l[u]=e[u])}return l}var Rn=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Ks(e){Rn(e)}function Js(e){console.error(e)}function ks(e){Rn(e)}function On(e,t){try{var l=e.onUncaughtError;l(t.value,{componentStack:t.stack})}catch(a){setTimeout(function(){throw a})}}function $s(e,t,l){try{var a=e.onCaughtError;a(l.value,{componentStack:l.stack,errorBoundary:t.tag===1?t.stateNode:null})}catch(u){setTimeout(function(){throw u})}}function Ac(e,t,l){return l=ul(l),l.tag=3,l.payload={element:null},l.callback=function(){On(e,t)},l}function Ws(e){return e=ul(e),e.tag=3,e}function Fs(e,t,l,a){var u=l.type.getDerivedStateFromError;if(typeof u=="function"){var n=a.value;e.payload=function(){return u(n)},e.callback=function(){$s(t,l,a)}}var c=l.stateNode;c!==null&&typeof c.componentDidCatch=="function"&&(e.callback=function(){$s(t,l,a),typeof u!="function"&&(ml===null?ml=new Set([this]):ml.add(this));var r=a.stack;this.componentDidCatch(a.value,{componentStack:r!==null?r:""})})}function Hm(e,t,l,a,u){if(l.flags|=32768,a!==null&&typeof a=="object"&&typeof a.then=="function"){if(t=l.alternate,t!==null&&Fa(t,l,u,!0),l=bt.current,l!==null){switch(l.tag){case 13:return Ot===null?kc():l.alternate===null&&Me===0&&(Me=3),l.flags&=-257,l.flags|=65536,l.lanes=u,a===Ii?l.flags|=16384:(t=l.updateQueue,t===null?l.updateQueue=new Set([a]):t.add(a),Wc(e,a,u)),!1;case 22:return l.flags|=65536,a===Ii?l.flags|=16384:(t=l.updateQueue,t===null?(t={transitions:null,markerInstances:null,retryQueue:new Set([a])},l.updateQueue=t):(l=t.retryQueue,l===null?t.retryQueue=new Set([a]):l.add(a)),Wc(e,a,u)),!1}throw Error(f(435,l.tag))}return Wc(e,a,u),kc(),!1}if(de)return t=bt.current,t!==null?((t.flags&65536)===0&&(t.flags|=256),t.flags|=65536,t.lanes=u,a!==Ki&&(e=Error(f(422),{cause:a}),Wa(mt(e,l)))):(a!==Ki&&(t=Error(f(423),{cause:a}),Wa(mt(t,l))),e=e.current.alternate,e.flags|=65536,u&=-u,e.lanes|=u,a=mt(a,l),u=Ac(e.stateNode,a,u),lc(e,u),Me!==4&&(Me=2)),!1;var n=Error(f(520),{cause:a});if(n=mt(n,l),gu===null?gu=[n]:gu.push(n),Me!==4&&(Me=2),t===null)return!0;a=mt(a,l),l=t;do{switch(l.tag){case 3:return l.flags|=65536,e=u&-u,l.lanes|=e,e=Ac(l.stateNode,a,e),lc(l,e),!1;case 1:if(t=l.type,n=l.stateNode,(l.flags&128)===0&&(typeof t.getDerivedStateFromError=="function"||n!==null&&typeof n.componentDidCatch=="function"&&(ml===null||!ml.has(n))))return l.flags|=65536,u&=-u,l.lanes|=u,u=Ws(u),Fs(u,e,l,a),lc(l,u),!1}l=l.return}while(l!==null);return!1}var Ps=Error(f(461)),Be=!1;function Le(e,t,l,a){t.child=e===null?Xs(t,null,l,a):ba(t,e.child,l,a)}function Is(e,t,l,a,u){l=l.render;var n=t.ref;if("ref"in a){var c={};for(var r in a)r!=="ref"&&(c[r]=a[r])}else c=a;return wl(t),a=cc(e,t,l,c,n,u),r=fc(),e!==null&&!Be?(rc(e,t,u),Qt(e,t,u)):(de&&r&&Zi(t),t.flags|=1,Le(e,t,a,u),t.child)}function eo(e,t,l,a,u){if(e===null){var n=l.type;return typeof n=="function"&&!Gi(n)&&n.defaultProps===void 0&&l.compare===null?(t.tag=15,t.type=n,to(e,t,n,a,u)):(e=un(l.type,null,a,t,t.mode,u),e.ref=t.ref,e.return=t,t.child=e)}if(n=e.child,!_c(e,u)){var c=n.memoizedProps;if(l=l.compare,l=l!==null?l:Ka,l(c,a)&&e.ref===t.ref)return Qt(e,t,u)}return t.flags|=1,e=Bt(n,a),e.ref=t.ref,e.return=t,t.child=e}function to(e,t,l,a,u){if(e!==null){var n=e.memoizedProps;if(Ka(n,a)&&e.ref===t.ref)if(Be=!1,t.pendingProps=a=n,_c(e,u))(e.flags&131072)!==0&&(Be=!0);else return t.lanes=e.lanes,Qt(e,t,u)}return Rc(e,t,l,a,u)}function lo(e,t,l){var a=t.pendingProps,u=a.children,n=e!==null?e.memoizedState:null;if(a.mode==="hidden"){if((t.flags&128)!==0){if(a=n!==null?n.baseLanes|l:l,e!==null){for(u=t.child=e.child,n=0;u!==null;)n=n|u.lanes|u.childLanes,u=u.sibling;t.childLanes=n&~a}else t.childLanes=0,t.child=null;return ao(e,t,a,l)}if((l&536870912)!==0)t.memoizedState={baseLanes:0,cachePool:null},e!==null&&sn(t,n!==null?n.cachePool:null),n!==null?ts(t,n):uc(),Qs(t);else return t.lanes=t.childLanes=536870912,ao(e,t,n!==null?n.baseLanes|l:l,l)}else n!==null?(sn(t,n.cachePool),ts(t,n),fl(),t.memoizedState=null):(e!==null&&sn(t,null),uc(),fl());return Le(e,t,u,l),t.child}function ao(e,t,l,a){var u=Pi();return u=u===null?null:{parent:Ce._currentValue,pool:u},t.memoizedState={baseLanes:l,cachePool:u},e!==null&&sn(t,null),uc(),Qs(t),e!==null&&Fa(e,t,a,!0),null}function Nn(e,t){var l=t.ref;if(l===null)e!==null&&e.ref!==null&&(t.flags|=4194816);else{if(typeof l!="function"&&typeof l!="object")throw Error(f(284));(e===null||e.ref!==l)&&(t.flags|=4194816)}}function Rc(e,t,l,a,u){return wl(t),l=cc(e,t,l,a,void 0,u),a=fc(),e!==null&&!Be?(rc(e,t,u),Qt(e,t,u)):(de&&a&&Zi(t),t.flags|=1,Le(e,t,l,u),t.child)}function uo(e,t,l,a,u,n){return wl(t),t.updateQueue=null,l=as(t,a,l,u),ls(e),a=fc(),e!==null&&!Be?(rc(e,t,n),Qt(e,t,n)):(de&&a&&Zi(t),t.flags|=1,Le(e,t,l,n),t.child)}function no(e,t,l,a,u){if(wl(t),t.stateNode===null){var n=fa,c=l.contextType;typeof c=="object"&&c!==null&&(n=Ve(c)),n=new l(a,n),t.memoizedState=n.state!==null&&n.state!==void 0?n.state:null,n.updater=Tc,t.stateNode=n,n._reactInternals=t,n=t.stateNode,n.props=a,n.state=t.memoizedState,n.refs={},ec(t),c=l.contextType,n.context=typeof c=="object"&&c!==null?Ve(c):fa,n.state=t.memoizedState,c=l.getDerivedStateFromProps,typeof c=="function"&&(Ec(t,l,c,a),n.state=t.memoizedState),typeof l.getDerivedStateFromProps=="function"||typeof n.getSnapshotBeforeUpdate=="function"||typeof n.UNSAFE_componentWillMount!="function"&&typeof n.componentWillMount!="function"||(c=n.state,typeof n.componentWillMount=="function"&&n.componentWillMount(),typeof n.UNSAFE_componentWillMount=="function"&&n.UNSAFE_componentWillMount(),c!==n.state&&Tc.enqueueReplaceState(n,n.state,null),uu(t,a,n,u),au(),n.state=t.memoizedState),typeof n.componentDidMount=="function"&&(t.flags|=4194308),a=!0}else if(e===null){n=t.stateNode;var r=t.memoizedProps,y=Gl(l,r);n.props=y;var T=n.context,D=l.contextType;c=fa,typeof D=="object"&&D!==null&&(c=Ve(D));var C=l.getDerivedStateFromProps;D=typeof C=="function"||typeof n.getSnapshotBeforeUpdate=="function",r=t.pendingProps!==r,D||typeof n.UNSAFE_componentWillReceiveProps!="function"&&typeof n.componentWillReceiveProps!="function"||(r||T!==c)&&Vs(t,n,a,c),al=!1;var R=t.memoizedState;n.state=R,uu(t,a,n,u),au(),T=t.memoizedState,r||R!==T||al?(typeof C=="function"&&(Ec(t,l,C,a),T=t.memoizedState),(y=al||Zs(t,l,y,a,R,T,c))?(D||typeof n.UNSAFE_componentWillMount!="function"&&typeof n.componentWillMount!="function"||(typeof n.componentWillMount=="function"&&n.componentWillMount(),typeof n.UNSAFE_componentWillMount=="function"&&n.UNSAFE_componentWillMount()),typeof n.componentDidMount=="function"&&(t.flags|=4194308)):(typeof n.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=a,t.memoizedState=T),n.props=a,n.state=T,n.context=c,a=y):(typeof n.componentDidMount=="function"&&(t.flags|=4194308),a=!1)}else{n=t.stateNode,tc(e,t),c=t.memoizedProps,D=Gl(l,c),n.props=D,C=t.pendingProps,R=n.context,T=l.contextType,y=fa,typeof T=="object"&&T!==null&&(y=Ve(T)),r=l.getDerivedStateFromProps,(T=typeof r=="function"||typeof n.getSnapshotBeforeUpdate=="function")||typeof n.UNSAFE_componentWillReceiveProps!="function"&&typeof n.componentWillReceiveProps!="function"||(c!==C||R!==y)&&Vs(t,n,a,y),al=!1,R=t.memoizedState,n.state=R,uu(t,a,n,u),au();var O=t.memoizedState;c!==C||R!==O||al||e!==null&&e.dependencies!==null&&fn(e.dependencies)?(typeof r=="function"&&(Ec(t,l,r,a),O=t.memoizedState),(D=al||Zs(t,l,D,a,R,O,y)||e!==null&&e.dependencies!==null&&fn(e.dependencies))?(T||typeof n.UNSAFE_componentWillUpdate!="function"&&typeof n.componentWillUpdate!="function"||(typeof n.componentWillUpdate=="function"&&n.componentWillUpdate(a,O,y),typeof n.UNSAFE_componentWillUpdate=="function"&&n.UNSAFE_componentWillUpdate(a,O,y)),typeof n.componentDidUpdate=="function"&&(t.flags|=4),typeof n.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof n.componentDidUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=4),typeof n.getSnapshotBeforeUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=1024),t.memoizedProps=a,t.memoizedState=O),n.props=a,n.state=O,n.context=y,a=D):(typeof n.componentDidUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=4),typeof n.getSnapshotBeforeUpdate!="function"||c===e.memoizedProps&&R===e.memoizedState||(t.flags|=1024),a=!1)}return n=a,Nn(e,t),a=(t.flags&128)!==0,n||a?(n=t.stateNode,l=a&&typeof l.getDerivedStateFromError!="function"?null:n.render(),t.flags|=1,e!==null&&a?(t.child=ba(t,e.child,null,u),t.child=ba(t,null,l,u)):Le(e,t,l,u),t.memoizedState=n.state,e=t.child):e=Qt(e,t,u),e}function io(e,t,l,a){return $a(),t.flags|=256,Le(e,t,l,a),t.child}var Oc={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function Nc(e){return{baseLanes:e,cachePool:Jr()}}function Mc(e,t,l){return e=e!==null?e.childLanes&~l:0,t&&(e|=pt),e}function co(e,t,l){var a=t.pendingProps,u=!1,n=(t.flags&128)!==0,c;if((c=n)||(c=e!==null&&e.memoizedState===null?!1:(Ue.current&2)!==0),c&&(u=!0,t.flags&=-129),c=(t.flags&32)!==0,t.flags&=-33,e===null){if(de){if(u?cl(t):fl(),de){var r=Ne,y;if(y=r){e:{for(y=r,r=Rt;y.nodeType!==8;){if(!r){r=null;break e}if(y=Tt(y.nextSibling),y===null){r=null;break e}}r=y}r!==null?(t.memoizedState={dehydrated:r,treeContext:Cl!==null?{id:qt,overflow:wt}:null,retryLane:536870912,hydrationErrors:null},y=nt(18,null,null,0),y.stateNode=r,y.return=t,t.child=y,ke=t,Ne=null,y=!0):y=!1}y||Bl(t)}if(r=t.memoizedState,r!==null&&(r=r.dehydrated,r!==null))return df(r)?t.lanes=32:t.lanes=536870912,null;Xt(t)}return r=a.children,a=a.fallback,u?(fl(),u=t.mode,r=Mn({mode:"hidden",children:r},u),a=_l(a,u,l,null),r.return=t,a.return=t,r.sibling=a,t.child=r,u=t.child,u.memoizedState=Nc(l),u.childLanes=Mc(e,c,l),t.memoizedState=Oc,a):(cl(t),zc(t,r))}if(y=e.memoizedState,y!==null&&(r=y.dehydrated,r!==null)){if(n)t.flags&256?(cl(t),t.flags&=-257,t=Dc(e,t,l)):t.memoizedState!==null?(fl(),t.child=e.child,t.flags|=128,t=null):(fl(),u=a.fallback,r=t.mode,a=Mn({mode:"visible",children:a.children},r),u=_l(u,r,l,null),u.flags|=2,a.return=t,u.return=t,a.sibling=u,t.child=a,ba(t,e.child,null,l),a=t.child,a.memoizedState=Nc(l),a.childLanes=Mc(e,c,l),t.memoizedState=Oc,t=u);else if(cl(t),df(r)){if(c=r.nextSibling&&r.nextSibling.dataset,c)var T=c.dgst;c=T,a=Error(f(419)),a.stack="",a.digest=c,Wa({value:a,source:null,stack:null}),t=Dc(e,t,l)}else if(Be||Fa(e,t,l,!1),c=(l&e.childLanes)!==0,Be||c){if(c=Se,c!==null&&(a=l&-l,a=(a&42)!==0?1:di(a),a=(a&(c.suspendedLanes|l))!==0?0:a,a!==0&&a!==y.retryLane))throw y.retryLane=a,ca(e,a),st(c,e,a),Ps;r.data==="$?"||kc(),t=Dc(e,t,l)}else r.data==="$?"?(t.flags|=192,t.child=e.child,t=null):(e=y.treeContext,Ne=Tt(r.nextSibling),ke=t,de=!0,Hl=null,Rt=!1,e!==null&&(vt[gt++]=qt,vt[gt++]=wt,vt[gt++]=Cl,qt=e.id,wt=e.overflow,Cl=t),t=zc(t,a.children),t.flags|=4096);return t}return u?(fl(),u=a.fallback,r=t.mode,y=e.child,T=y.sibling,a=Bt(y,{mode:"hidden",children:a.children}),a.subtreeFlags=y.subtreeFlags&65011712,T!==null?u=Bt(T,u):(u=_l(u,r,l,null),u.flags|=2),u.return=t,a.return=t,a.sibling=u,t.child=a,a=u,u=t.child,r=e.child.memoizedState,r===null?r=Nc(l):(y=r.cachePool,y!==null?(T=Ce._currentValue,y=y.parent!==T?{parent:T,pool:T}:y):y=Jr(),r={baseLanes:r.baseLanes|l,cachePool:y}),u.memoizedState=r,u.childLanes=Mc(e,c,l),t.memoizedState=Oc,a):(cl(t),l=e.child,e=l.sibling,l=Bt(l,{mode:"visible",children:a.children}),l.return=t,l.sibling=null,e!==null&&(c=t.deletions,c===null?(t.deletions=[e],t.flags|=16):c.push(e)),t.child=l,t.memoizedState=null,l)}function zc(e,t){return t=Mn({mode:"visible",children:t},e.mode),t.return=e,e.child=t}function Mn(e,t){return e=nt(22,e,null,t),e.lanes=0,e.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null},e}function Dc(e,t,l){return ba(t,e.child,null,l),e=zc(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function fo(e,t,l){e.lanes|=t;var a=e.alternate;a!==null&&(a.lanes|=t),ki(e.return,t,l)}function jc(e,t,l,a,u){var n=e.memoizedState;n===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:a,tail:l,tailMode:u}:(n.isBackwards=t,n.rendering=null,n.renderingStartTime=0,n.last=a,n.tail=l,n.tailMode=u)}function ro(e,t,l){var a=t.pendingProps,u=a.revealOrder,n=a.tail;if(Le(e,t,a.children,l),a=Ue.current,(a&2)!==0)a=a&1|2,t.flags|=128;else{if(e!==null&&(e.flags&128)!==0)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&fo(e,l,t);else if(e.tag===19)fo(e,l,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}a&=1}switch(Y(Ue,a),u){case"forwards":for(l=t.child,u=null;l!==null;)e=l.alternate,e!==null&&An(e)===null&&(u=l),l=l.sibling;l=u,l===null?(u=t.child,t.child=null):(u=l.sibling,l.sibling=null),jc(t,!1,u,l,n);break;case"backwards":for(l=null,u=t.child,t.child=null;u!==null;){if(e=u.alternate,e!==null&&An(e)===null){t.child=u;break}e=u.sibling,u.sibling=l,l=u,u=e}jc(t,!0,l,null,n);break;case"together":jc(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function Qt(e,t,l){if(e!==null&&(t.dependencies=e.dependencies),hl|=t.lanes,(l&t.childLanes)===0)if(e!==null){if(Fa(e,t,l,!1),(l&t.childLanes)===0)return null}else return null;if(e!==null&&t.child!==e.child)throw Error(f(153));if(t.child!==null){for(e=t.child,l=Bt(e,e.pendingProps),t.child=l,l.return=t;e.sibling!==null;)e=e.sibling,l=l.sibling=Bt(e,e.pendingProps),l.return=t;l.sibling=null}return t.child}function _c(e,t){return(e.lanes&t)!==0?!0:(e=e.dependencies,!!(e!==null&&fn(e)))}function Bm(e,t,l){switch(t.tag){case 3:Ee(t,t.stateNode.containerInfo),ll(t,Ce,e.memoizedState.cache),$a();break;case 27:case 5:ci(t);break;case 4:Ee(t,t.stateNode.containerInfo);break;case 10:ll(t,t.type,t.memoizedProps.value);break;case 13:var a=t.memoizedState;if(a!==null)return a.dehydrated!==null?(cl(t),t.flags|=128,null):(l&t.child.childLanes)!==0?co(e,t,l):(cl(t),e=Qt(e,t,l),e!==null?e.sibling:null);cl(t);break;case 19:var u=(e.flags&128)!==0;if(a=(l&t.childLanes)!==0,a||(Fa(e,t,l,!1),a=(l&t.childLanes)!==0),u){if(a)return ro(e,t,l);t.flags|=128}if(u=t.memoizedState,u!==null&&(u.rendering=null,u.tail=null,u.lastEffect=null),Y(Ue,Ue.current),a)break;return null;case 22:case 23:return t.lanes=0,lo(e,t,l);case 24:ll(t,Ce,e.memoizedState.cache)}return Qt(e,t,l)}function so(e,t,l){if(e!==null)if(e.memoizedProps!==t.pendingProps)Be=!0;else{if(!_c(e,l)&&(t.flags&128)===0)return Be=!1,Bm(e,t,l);Be=(e.flags&131072)!==0}else Be=!1,de&&(t.flags&1048576)!==0&&Yr(t,cn,t.index);switch(t.lanes=0,t.tag){case 16:e:{e=t.pendingProps;var a=t.elementType,u=a._init;if(a=u(a._payload),t.type=a,typeof a=="function")Gi(a)?(e=Gl(a,e),t.tag=1,t=no(null,t,a,e,l)):(t.tag=0,t=Rc(null,t,a,e,l));else{if(a!=null){if(u=a.$$typeof,u===ce){t.tag=11,t=Is(null,t,a,e,l);break e}else if(u===ue){t.tag=14,t=eo(null,t,a,e,l);break e}}throw t=Ol(a)||a,Error(f(306,t,""))}}return t;case 0:return Rc(e,t,t.type,t.pendingProps,l);case 1:return a=t.type,u=Gl(a,t.pendingProps),no(e,t,a,u,l);case 3:e:{if(Ee(t,t.stateNode.containerInfo),e===null)throw Error(f(387));a=t.pendingProps;var n=t.memoizedState;u=n.element,tc(e,t),uu(t,a,null,l);var c=t.memoizedState;if(a=c.cache,ll(t,Ce,a),a!==n.cache&&$i(t,[Ce],l,!0),au(),a=c.element,n.isDehydrated)if(n={element:a,isDehydrated:!1,cache:c.cache},t.updateQueue.baseState=n,t.memoizedState=n,t.flags&256){t=io(e,t,a,l);break e}else if(a!==u){u=mt(Error(f(424)),t),Wa(u),t=io(e,t,a,l);break e}else{switch(e=t.stateNode.containerInfo,e.nodeType){case 9:e=e.body;break;default:e=e.nodeName==="HTML"?e.ownerDocument.body:e}for(Ne=Tt(e.firstChild),ke=t,de=!0,Hl=null,Rt=!0,l=Xs(t,null,a,l),t.child=l;l;)l.flags=l.flags&-3|4096,l=l.sibling}else{if($a(),a===u){t=Qt(e,t,l);break e}Le(e,t,a,l)}t=t.child}return t;case 26:return Nn(e,t),e===null?(l=yd(t.type,null,t.pendingProps,null))?t.memoizedState=l:de||(l=t.type,e=t.pendingProps,a=Xn(ee.current).createElement(l),a[Ze]=t,a[$e]=e,Ge(a,l,e),He(a),t.stateNode=a):t.memoizedState=yd(t.type,e.memoizedProps,t.pendingProps,e.memoizedState),null;case 27:return ci(t),e===null&&de&&(a=t.stateNode=dd(t.type,t.pendingProps,ee.current),ke=t,Rt=!0,u=Ne,gl(t.type)?(hf=u,Ne=Tt(a.firstChild)):Ne=u),Le(e,t,t.pendingProps.children,l),Nn(e,t),e===null&&(t.flags|=4194304),t.child;case 5:return e===null&&de&&((u=a=Ne)&&(a=sy(a,t.type,t.pendingProps,Rt),a!==null?(t.stateNode=a,ke=t,Ne=Tt(a.firstChild),Rt=!1,u=!0):u=!1),u||Bl(t)),ci(t),u=t.type,n=t.pendingProps,c=e!==null?e.memoizedProps:null,a=n.children,rf(u,n)?a=null:c!==null&&rf(u,c)&&(t.flags|=32),t.memoizedState!==null&&(u=cc(e,t,Mm,null,null,l),Ou._currentValue=u),Nn(e,t),Le(e,t,a,l),t.child;case 6:return e===null&&de&&((e=l=Ne)&&(l=oy(l,t.pendingProps,Rt),l!==null?(t.stateNode=l,ke=t,Ne=null,e=!0):e=!1),e||Bl(t)),null;case 13:return co(e,t,l);case 4:return Ee(t,t.stateNode.containerInfo),a=t.pendingProps,e===null?t.child=ba(t,null,a,l):Le(e,t,a,l),t.child;case 11:return Is(e,t,t.type,t.pendingProps,l);case 7:return Le(e,t,t.pendingProps,l),t.child;case 8:return Le(e,t,t.pendingProps.children,l),t.child;case 12:return Le(e,t,t.pendingProps.children,l),t.child;case 10:return a=t.pendingProps,ll(t,t.type,a.value),Le(e,t,a.children,l),t.child;case 9:return u=t.type._context,a=t.pendingProps.children,wl(t),u=Ve(u),a=a(u),t.flags|=1,Le(e,t,a,l),t.child;case 14:return eo(e,t,t.type,t.pendingProps,l);case 15:return to(e,t,t.type,t.pendingProps,l);case 19:return ro(e,t,l);case 31:return a=t.pendingProps,l=t.mode,a={mode:a.mode,children:a.children},e===null?(l=Mn(a,l),l.ref=t.ref,t.child=l,l.return=t,t=l):(l=Bt(e.child,a),l.ref=t.ref,t.child=l,l.return=t,t=l),t;case 22:return lo(e,t,l);case 24:return wl(t),a=Ve(Ce),e===null?(u=Pi(),u===null&&(u=Se,n=Wi(),u.pooledCache=n,n.refCount++,n!==null&&(u.pooledCacheLanes|=l),u=n),t.memoizedState={parent:a,cache:u},ec(t),ll(t,Ce,u)):((e.lanes&l)!==0&&(tc(e,t),uu(t,null,null,l),au()),u=e.memoizedState,n=t.memoizedState,u.parent!==a?(u={parent:a,cache:a},t.memoizedState=u,t.lanes===0&&(t.memoizedState=t.updateQueue.baseState=u),ll(t,Ce,a)):(a=n.cache,ll(t,Ce,a),a!==u.cache&&$i(t,[Ce],l,!0))),Le(e,t,t.pendingProps.children,l),t.child;case 29:throw t.pendingProps}throw Error(f(156,t.tag))}function Zt(e){e.flags|=4}function oo(e,t){if(t.type!=="stylesheet"||(t.state.loading&4)!==0)e.flags&=-16777217;else if(e.flags|=16777216,!Sd(t)){if(t=bt.current,t!==null&&((fe&4194048)===fe?Ot!==null:(fe&62914560)!==fe&&(fe&536870912)===0||t!==Ot))throw tu=Ii,kr;e.flags|=8192}}function zn(e,t){t!==null&&(e.flags|=4),e.flags&16384&&(t=e.tag!==22?Qf():536870912,e.lanes|=t,Ea|=t)}function ou(e,t){if(!de)switch(e.tailMode){case"hidden":t=e.tail;for(var l=null;t!==null;)t.alternate!==null&&(l=t),t=t.sibling;l===null?e.tail=null:l.sibling=null;break;case"collapsed":l=e.tail;for(var a=null;l!==null;)l.alternate!==null&&(a=l),l=l.sibling;a===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:a.sibling=null}}function Ae(e){var t=e.alternate!==null&&e.alternate.child===e.child,l=0,a=0;if(t)for(var u=e.child;u!==null;)l|=u.lanes|u.childLanes,a|=u.subtreeFlags&65011712,a|=u.flags&65011712,u.return=e,u=u.sibling;else for(u=e.child;u!==null;)l|=u.lanes|u.childLanes,a|=u.subtreeFlags,a|=u.flags,u.return=e,u=u.sibling;return e.subtreeFlags|=a,e.childLanes=l,t}function qm(e,t,l){var a=t.pendingProps;switch(Vi(t),t.tag){case 31:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Ae(t),null;case 1:return Ae(t),null;case 3:return l=t.stateNode,a=null,e!==null&&(a=e.memoizedState.cache),t.memoizedState.cache!==a&&(t.flags|=2048),Yt(Ce),Pt(),l.pendingContext&&(l.context=l.pendingContext,l.pendingContext=null),(e===null||e.child===null)&&(ka(t)?Zt(t):e===null||e.memoizedState.isDehydrated&&(t.flags&256)===0||(t.flags|=1024,Qr())),Ae(t),null;case 26:return l=t.memoizedState,e===null?(Zt(t),l!==null?(Ae(t),oo(t,l)):(Ae(t),t.flags&=-16777217)):l?l!==e.memoizedState?(Zt(t),Ae(t),oo(t,l)):(Ae(t),t.flags&=-16777217):(e.memoizedProps!==a&&Zt(t),Ae(t),t.flags&=-16777217),null;case 27:Lu(t),l=ee.current;var u=t.type;if(e!==null&&t.stateNode!=null)e.memoizedProps!==a&&Zt(t);else{if(!a){if(t.stateNode===null)throw Error(f(166));return Ae(t),null}e=J.current,ka(t)?Gr(t):(e=dd(u,a,l),t.stateNode=e,Zt(t))}return Ae(t),null;case 5:if(Lu(t),l=t.type,e!==null&&t.stateNode!=null)e.memoizedProps!==a&&Zt(t);else{if(!a){if(t.stateNode===null)throw Error(f(166));return Ae(t),null}if(e=J.current,ka(t))Gr(t);else{switch(u=Xn(ee.current),e){case 1:e=u.createElementNS("http://www.w3.org/2000/svg",l);break;case 2:e=u.createElementNS("http://www.w3.org/1998/Math/MathML",l);break;default:switch(l){case"svg":e=u.createElementNS("http://www.w3.org/2000/svg",l);break;case"math":e=u.createElementNS("http://www.w3.org/1998/Math/MathML",l);break;case"script":e=u.createElement("div"),e.innerHTML=" + + + +
+ + + diff --git a/components/rest_api/webfolder/vite.svg b/components/rest_api/webfolder/vite.svg new file mode 100755 index 0000000..e7b8dfb --- /dev/null +++ b/components/rest_api/webfolder/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components/serial_sync/src/sync_master.c b/components/serial_sync/src/sync_master.c index 4d092f1..e744b35 100755 --- a/components/serial_sync/src/sync_master.c +++ b/components/serial_sync/src/sync_master.c @@ -349,11 +349,11 @@ void handlePacket(uint8_t *buf, int len) printf("Received max_grid_current %i\n", (int)msg_in.payload.max_grid_current); int max_grid_current = (int)msg_in.payload.max_grid_current; - + /* if (max_grid_current != grid_get_max_current()) { send_max_grid_current(grid_get_max_current()); - } + }*/ break; case LoToHi_lock_state_tag: @@ -414,7 +414,7 @@ void master_sync_start() ESP_LOGI(TAG, "Master SYNC Serial"); init(); - xTaskCreate(rx_task, "uart_rx_task", 1024 * 5, NULL, 5, NULL); + xTaskCreate(rx_task, "uart_rx_task", 1024 * 5, NULL, 3, NULL); //xTaskCreate(tx_task, "uart_tx_task", 1024 * 5, NULL, 5, NULL); } diff --git a/components/serial_sync/src/sync_slave.c b/components/serial_sync/src/sync_slave.c index 0161160..6aaf441 100755 --- a/components/serial_sync/src/sync_slave.c +++ b/components/serial_sync/src/sync_slave.c @@ -322,7 +322,7 @@ void handlePacket(uint8_t *buf, int len) case HiToLo_max_grid_current_tag: printf("Received max_grid_current %i\n", (int)msg_in.payload.max_grid_current); - grid_set_max_current((int)msg_in.payload.max_grid_current); + //grid_set_max_current((int)msg_in.payload.max_grid_current); break; case HiToLo_allow_power_on_tag: printf("Received allow_poweron %i\n", @@ -335,8 +335,8 @@ void handlePacket(uint8_t *buf, int len) printf("Received grid_current %i\n", (int)msg_in.payload.grid_current); - setMaxGridCurrent(grid_get_max_current() * 10); - setLiveGridCurrent((int)msg_in.payload.grid_current); + //setMaxGridCurrent(grid_get_max_current() * 10); + //setLiveGridCurrent((int)msg_in.payload.grid_current); break; default: @@ -436,7 +436,7 @@ static void tx_task(void *arg) vTaskDelay(5000 / portTICK_PERIOD_MS); - send_max_grid_current(grid_get_max_current()); + //send_max_grid_current(grid_get_max_current()); vTaskDelay(5000 / portTICK_PERIOD_MS); // send_lock_state(false); @@ -500,8 +500,8 @@ void slave_sync_start() ESP_LOGI(TAG, "Starting SYNC Serial"); init(); - xTaskCreate(rx_task, "uart_rx_task", 1024 * 5, NULL, 5, NULL); - xTaskCreate(tx_task, "uart_tx_task", 1024 * 5, NULL, 5, NULL); + xTaskCreate(rx_task, "uart_rx_task", 1024 * 5, NULL, 3, NULL); + xTaskCreate(tx_task, "uart_tx_task", 1024 * 5, NULL, 3, NULL); } void slave_sync_stop(void) diff --git a/main/main.c b/main/main.c index 40fda16..d04e675 100755 --- a/main/main.c +++ b/main/main.c @@ -1,237 +1,181 @@ #include #include -#include -#include "sdkconfig.h" +#include + #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/event_groups.h" -#include "esp_ota_ops.h" #include "esp_log.h" #include "esp_err.h" -#include "nvs_flash.h" #include "esp_event.h" +#include "esp_netif.h" #include "esp_spiffs.h" +#include "esp_system.h" +#include "nvs_flash.h" #include "driver/gpio.h" -#include "evse_api.h" -#include "evse_manager.h" -#include "peripherals.h" -#include "led.h" -#include "api.h" -#include "protocols.h" -#include "meter_zigbee.h" -#include "board_config.h" #include "wifi.h" +#include "board_config.h" #include "logger.h" -#include "loadbalancer.h" +#include "rest_main.h" +#include "peripherals.h" +#include "protocols.h" +#include "evse_manager.h" +#include "evse_api.h" #include "auth.h" +#include "loadbalancer.h" +#include "meter_manager.h" -#define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo -#define AP_CONNECTION_TIMEOUT 60000 // 60sec -#define RESET_HOLD_TIME 10000 // 10sec -#define PRESS_BIT BIT0 -#define RELEASED_BIT BIT1 +#define EVSE_MANAGER_TICK_PERIOD_MS 1000 +#define AP_CONNECTION_TIMEOUT 120000 +#define RESET_HOLD_TIME 10000 +#define DEBOUNCE_TIME_MS 50 + +#define PRESS_BIT BIT0 +#define RELEASED_BIT BIT1 static const char *TAG = "app_main"; + static TaskHandle_t user_input_task; - -static bool pressed = false; // Variável para verificar se o botão foi pressionado -static TickType_t press_tick = 0; // Variável para armazenar o tempo de pressionamento do botão +static TickType_t press_tick = 0; +static TickType_t last_interrupt_tick = 0; +static bool pressed = false; -static void reset_and_reboot(void) -{ - ESP_LOGW(TAG, "All settings will be erased..."); - ESP_ERROR_CHECK(nvs_flash_erase()); - - ESP_LOGW(TAG, "Rebooting..."); - vTaskDelay(pdMS_TO_TICKS(500)); - - esp_restart(); -} - -static void wifi_event_task_func(void *param) -{ - EventBits_t mode_bits; - while (true) - { - mode_bits = xEventGroupWaitBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); - if (mode_bits & WIFI_AP_MODE_BIT) - { - if (xEventGroupWaitBits(wifi_event_group, WIFI_AP_CONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & WIFI_AP_CONNECTED_BIT) - { - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_AP_DISCONNECTED_BIT)); - } - else - { - if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) - { - wifi_ap_stop(); - } - } - } - else if (mode_bits & WIFI_STA_MODE_BIT) - { - if (xEventGroupWaitBits(wifi_event_group, WIFI_STA_CONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_CONNECTED_BIT) - { - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_DISCONNECTED_BIT)); - } - } - } -} - - - -static void handle_button_press(void) -{ - if (xTaskGetTickCount() - press_tick >= pdMS_TO_TICKS(RESET_HOLD_TIME)) { - evse_set_available(false); - reset_and_reboot(); - } else { - if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) { - wifi_ap_start(); - } - } -} - -static void handle_button_release(void) -{ - // Lógica quando o botão for liberado - pressed = false; -} - -static void user_input_task_func(void *param) -{ - uint32_t notification; - while (true) - { - if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) - { - if (notification & PRESS_BIT) - { - press_tick = xTaskGetTickCount(); - pressed = true; - } - if (notification & RELEASED_BIT) - { - if (pressed) - { - handle_button_press(); - } - else - { - handle_button_release(); - } - } - } - } -} - - -static void IRAM_ATTR button_isr_handler(void *arg) -{ - BaseType_t higher_task_woken = pdFALSE; - - if (!gpio_get_level(board_config.button_wifi_gpio)) - { - xTaskNotifyFromISR(user_input_task, RELEASED_BIT, eSetBits, &higher_task_woken); - } - else - { - xTaskNotifyFromISR(user_input_task, PRESS_BIT, eSetBits, &higher_task_woken); - } - - if (higher_task_woken) - { - portYIELD_FROM_ISR(); - } -} - -static void button_init(void) -{ - gpio_config_t conf = { - .pin_bit_mask = BIT64(board_config.button_wifi_gpio), - .mode = GPIO_MODE_INPUT, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .pull_up_en = GPIO_PULLUP_ENABLE, - .intr_type = GPIO_INTR_ANYEDGE}; - ESP_ERROR_CHECK(gpio_config(&conf)); - ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); -} - -static void fs_info(esp_vfs_spiffs_conf_t *conf) -{ +// +// File system (SPIFFS) init and info +// +static void fs_info(esp_vfs_spiffs_conf_t *conf) { size_t total = 0, used = 0; esp_err_t ret = esp_spiffs_info(conf->partition_label, &total, &used); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to get partition %s information %s", conf->partition_label, esp_err_to_name(ret)); - } + if (ret == ESP_OK) + ESP_LOGI(TAG, "Partition %s: total: %d, used: %d", conf->partition_label, total, used); else - { - ESP_LOGI(TAG, "Partition %s size: total: %d, used: %d", conf->partition_label, total, used); - } + ESP_LOGE(TAG, "Failed to get SPIFFS info: %s", esp_err_to_name(ret)); } -static void fs_init(void) -{ +static void fs_init(void) { esp_vfs_spiffs_conf_t cfg_conf = { .base_path = "/cfg", .partition_label = "cfg", .max_files = 1, - .format_if_mount_failed = false}; - esp_err_t ret = esp_vfs_spiffs_register(&cfg_conf); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to mount SPIFFS partition 'cfg'. Error: %s", esp_err_to_name(ret)); - return; // Ou reinicie o dispositivo dependendo do caso - } + .format_if_mount_failed = false + }; esp_vfs_spiffs_conf_t data_conf = { .base_path = "/data", .partition_label = "data", .max_files = 5, - .format_if_mount_failed = true}; - ret = esp_vfs_spiffs_register(&data_conf); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to mount SPIFFS partition 'data'. Error: %s", esp_err_to_name(ret)); - return; // Ou reinicie o dispositivo dependendo do caso - } + .format_if_mount_failed = true + }; + + ESP_ERROR_CHECK(esp_vfs_spiffs_register(&cfg_conf)); + ESP_ERROR_CHECK(esp_vfs_spiffs_register(&data_conf)); fs_info(&cfg_conf); fs_info(&data_conf); } -static bool ota_diagnostic(void) -{ - // TODO diagnostic after ota - return true; +// +// Wi-Fi event monitoring task +// +static void wifi_event_task_func(void *param) { + EventBits_t mode_bits; + while (1) { + mode_bits = xEventGroupWaitBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); + + if (mode_bits & WIFI_AP_MODE_BIT) { + if (xEventGroupWaitBits(wifi_event_group, WIFI_AP_CONNECTED_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & WIFI_AP_CONNECTED_BIT) { + xEventGroupWaitBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); + } else { + if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) { + //wifi_ap_stop(); + } + } + } else if (mode_bits & WIFI_STA_MODE_BIT) { + xEventGroupWaitBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY); + } + } } -static void init_modules(void) -{ - - QueueHandle_t auth_queue = xQueueCreate(10, sizeof(auth_event_t)); +// +// Botão e tratamento +// +static void handle_button_press(void) { + ESP_LOGI(TAG, "Ativando modo AP"); + if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) { + wifi_ap_start(); + } +} +static void user_input_task_func(void *param) { + uint32_t notification; + while (1) { + if (xTaskNotifyWait(0x00, 0xFF, ¬ification, portMAX_DELAY)) { + if (notification & PRESS_BIT) { + press_tick = xTaskGetTickCount(); + pressed = true; + ESP_LOGI(TAG, "Botão pressionado"); + } - wifi_ini(); + if (notification & RELEASED_BIT && pressed) { + pressed = false; + ESP_LOGI(TAG, "Botão liberado"); + handle_button_press(); + } + } + } +} + +static void IRAM_ATTR button_isr_handler(void *arg) { + BaseType_t higher_task_woken = pdFALSE; + TickType_t now = xTaskGetTickCountFromISR(); + + if (now - last_interrupt_tick < pdMS_TO_TICKS(DEBOUNCE_TIME_MS)) return; + last_interrupt_tick = now; + + if (!gpio_get_level(board_config.button_wifi_gpio)) { + xTaskNotifyFromISR(user_input_task, RELEASED_BIT, eSetBits, &higher_task_woken); + } else { + xTaskNotifyFromISR(user_input_task, PRESS_BIT, eSetBits, &higher_task_woken); + } + + if (higher_task_woken) { + portYIELD_FROM_ISR(); + } +} + +static void button_init(void) { + gpio_config_t conf = { + .pin_bit_mask = BIT64(board_config.button_wifi_gpio), + .mode = GPIO_MODE_INPUT, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .pull_up_en = GPIO_PULLUP_ENABLE, + .intr_type = GPIO_INTR_ANYEDGE + }; + ESP_ERROR_CHECK(gpio_config(&conf)); + ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); +} + +// +// Inicialização dos módulos do sistema +// +static void init_modules(void) { peripherals_init(); - api_init(); + //api_init(); + ESP_ERROR_CHECK(rest_server_init("/data")); protocols_init(); evse_manager_init(); evse_init(); // Cria a task para FSM button_init(); - auth_init(); - auth_set_event_queue(auth_queue); - evse_manager_start(auth_queue); loadbalancer_init(); - + meter_manager_grid_init(); + meter_manager_grid_start(); + //meter_manager_evse_init(); // Outros módulos (descomente conforme necessário) // meter_init(); @@ -244,36 +188,18 @@ static void init_modules(void) // slave_sync_start(); } -void app_main(void) -{ +// +// Função principal do firmware +// +void app_main(void) { logger_init(); esp_log_set_vprintf(logger_vprintf); - const esp_partition_t *running = esp_ota_get_running_partition(); - ESP_LOGI(TAG, "Running partition: %s", running->label); - - esp_ota_img_states_t ota_state; - if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) - { - if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) - { - ESP_LOGI(TAG, "OTA pending verify"); - if (ota_diagnostic()) - { - ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ..."); - esp_ota_mark_app_valid_cancel_rollback(); - } - else - { - ESP_LOGE(TAG, "Diagnostics failed! Starting rollback to the previous version ..."); - esp_ota_mark_app_invalid_rollback_and_reboot(); - } - } - } + esp_reset_reason_t reason = esp_reset_reason(); + ESP_LOGI(TAG, "Reset reason: %d", reason); esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGW(TAG, "Erasing NVS flash"); ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); @@ -286,13 +212,10 @@ void app_main(void) ESP_ERROR_CHECK(gpio_install_isr_service(0)); board_config_load(); - + wifi_ini(); + //wifi_ap_start(); init_modules(); - xTaskCreate(wifi_event_task_func, "wifi_event_task", 4 * 1024, NULL, 5, NULL); - xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 5, &user_input_task); - - - - // Loop principal não é necessário se tudo roda por tasks + xTaskCreate(wifi_event_task_func, "wifi_event_task", 8 * 1024, NULL, 3, NULL); + xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 3, &user_input_task); } diff --git a/main_back b/main_back deleted file mode 100755 index 3700349..0000000 --- a/main_back +++ /dev/null @@ -1,375 +0,0 @@ - -#include -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "esp_ota_ops.h" -#include "esp_log.h" -#include "esp_err.h" -#include "nvs_flash.h" -#include "esp_event.h" -#include "esp_spiffs.h" -#include "driver/gpio.h" - -#include "evse_api.h" -#include "peripherals.h" -#include "led.h" -// #include "api.h" -// #include "protocols.h" -#include "serial_mt.h" -#include "board_config.h" -// #include "wifi.h" -#include "logger.h" -#include "ocpp.h" -#include "currentshaper.h" -// #include "serial_mdb.h" -#include "meter.h" -// #include "rc522_2.h" -//#include "main_wiegand.h" -#include "app_main.h" - -// #include "sync_slave.h" -// #include "sync_master.h" -// #define AP_CONNECTION_TIMEOUT 60000 // 60sec -// #define RESET_HOLD_TIME 10000 // 10sec - -// #define PRESS_BIT BIT0 -// #define RELEASED_BIT BIT1 - -static const char *TAG = "app_main"; - -// static TaskHandle_t user_input_task; - -static TaskHandle_t evse_task; - -static evse_state_t led_state = -1; - -/* -static void reset_and_reboot(void) -{ - ESP_LOGW(TAG, "All settings will be erased..."); - ESP_ERROR_CHECK(nvs_flash_erase()); - - ESP_LOGW(TAG, "Rebooting..."); - vTaskDelay(pdMS_TO_TICKS(500)); - - esp_restart(); -} - - -static void wifi_event_task_func(void *param) -{ - EventBits_t mode_bits; - - while (true) - { - led_set_off(LED_ID_WIFI); - mode_bits = xEventGroupWaitBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); - if (mode_bits & WIFI_AP_MODE_BIT) - { - led_set_state(LED_ID_WIFI, 100, 900); - - if (xEventGroupWaitBits(wifi_event_group, WIFI_AP_CONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & WIFI_AP_CONNECTED_BIT) - { - led_set_state(LED_ID_WIFI, 1900, 100); - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_AP_DISCONNECTED_BIT)); - } - else - { - if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) - { - serial_mdb_set_meter_test(false); - wifi_ap_stop(); - } - } - } - else if (mode_bits & WIFI_STA_MODE_BIT) - { - led_set_state(LED_ID_WIFI, 500, 500); - - if (xEventGroupWaitBits(wifi_event_group, WIFI_STA_CONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_CONNECTED_BIT) - { - led_set_on(LED_ID_WIFI); - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_DISCONNECTED_BIT)); - } - } - } -} - -static void user_input_task_func(void *param) -{ - uint32_t notification; - - bool pressed = false; - TickType_t press_tick = 0; - - while (true) - { - if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) - { - if (notification & PRESS_BIT) - { - press_tick = xTaskGetTickCount(); - pressed = true; - } - if (notification & RELEASED_BIT) - { - if (pressed) - { // sometimes after connect debug UART emit RELEASED_BIT without preceding PRESS_BIT - if (xTaskGetTickCount() - press_tick >= pdMS_TO_TICKS(RESET_HOLD_TIME)) - { - evse_set_available(false); - reset_and_reboot(); - } - else - { - if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) - { - wifi_ap_start(); - serial_mdb_set_meter_test(true); - } - } - } - pressed = false; - } - } - } -} - -static void IRAM_ATTR button_isr_handler(void *arg) -{ - BaseType_t higher_task_woken = pdFALSE; - - if (!gpio_get_level(board_config.button_wifi_gpio)) - { - xTaskNotifyFromISR(user_input_task, RELEASED_BIT, eSetBits, &higher_task_woken); - } - else - { - xTaskNotifyFromISR(user_input_task, PRESS_BIT, eSetBits, &higher_task_woken); - } - - if (higher_task_woken) - { - portYIELD_FROM_ISR(); - } -} - -static void button_init(void) -{ - gpio_config_t conf = { - .pin_bit_mask = BIT64(board_config.button_wifi_gpio), - .mode = GPIO_MODE_INPUT, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .pull_up_en = GPIO_PULLUP_ENABLE, - .intr_type = GPIO_INTR_ANYEDGE}; - ESP_ERROR_CHECK(gpio_config(&conf)); - ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); -} - -static void button_init(void) -{ - gpio_set_direction(GPIO_NUM_25, GPIO_MODE_OUTPUT); - gpio_pulldown_en(GPIO_NUM_25); - gpio_set_level(GPIO_NUM_25, 0); -}*/ - -static void fs_info(esp_vfs_spiffs_conf_t *conf) -{ - size_t total = 0, used = 0; - esp_err_t ret = esp_spiffs_info(conf->partition_label, &total, &used); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to get partition %s information %s", conf->partition_label, esp_err_to_name(ret)); - } - else - { - ESP_LOGI(TAG, "Partition %s size: total: %d, used: %d", conf->partition_label, total, used); - } -} - -static void fs_init(void) -{ - esp_vfs_spiffs_conf_t cfg_conf = { - .base_path = "/cfg", - .partition_label = "cfg", - .max_files = 1, - .format_if_mount_failed = false}; - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&cfg_conf)); - - esp_vfs_spiffs_conf_t data_conf = { - .base_path = "/data", - .partition_label = "data", - .max_files = 5, - .format_if_mount_failed = true}; - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&data_conf)); - - fs_info(&cfg_conf); - fs_info(&data_conf); -} - -static bool ota_diagnostic(void) -{ - // TODO diagnostic after ota - return true; -} - -static void update_leds(void) -{ - if (led_state != evse_get_state()) - { - led_state = evse_get_state(); - - switch (led_state) - { - case EVSE_STATE_A: - led_set_off(LED_ID_CHARGING); - led_set_off(LED_ID_ERROR); - led_set_on(LED_ID_WIFI); - break; - case EVSE_STATE_B1: - case EVSE_STATE_B2: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_on(LED_ID_CHARGING); - break; - case EVSE_STATE_C1: - case EVSE_STATE_D1: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_CHARGING, 1000, 1000); - break; - case EVSE_STATE_C2: - case EVSE_STATE_D2: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_CHARGING, 1000, 500); - led_set_buzzer(); - break; - case EVSE_STATE_E: - led_set_off(LED_ID_WIFI); - led_set_off(LED_ID_CHARGING); - led_set_state(LED_ID_ERROR, 500, 500); - break; - case EVSE_STATE_F: - led_set_off(LED_ID_CHARGING); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_ERROR, 500, 500); - break; - } - } -} - -static void evse_task_func(void *param) -{ - while (true) - { - evse_process(); - update_leds(); - // ESP_LOGI(TAG, "getPower %d", getDataMeter().wattA); - vTaskDelay(pdMS_TO_TICKS(100)); - } -} - -void app_main(void) -{ - - logger_init(); - esp_log_set_vprintf(logger_vprintf); - - const esp_partition_t *running = esp_ota_get_running_partition(); - ESP_LOGI(TAG, "Running partition: %s", running->label); - - esp_ota_img_states_t ota_state; - if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) - { - if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) - { - ESP_LOGI(TAG, "OTA pending verify"); - if (ota_diagnostic()) - { - ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ..."); - esp_ota_mark_app_valid_cancel_rollback(); - } - else - { - ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ..."); - esp_ota_mark_app_invalid_rollback_and_reboot(); - } - } - } - - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_LOGW(TAG, "Erasing NVS flash"); - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - fs_init(); - - // ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - ESP_ERROR_CHECK(gpio_install_isr_service(0)); - - board_config_load(); - - // wifi_ini(); - - peripherals_init(); - - // api_init(); - - // protocols_init(); - - evse_init(); - - // button_init(); - - // xTaskCreate(wifi_event_task_func, "wifi_event_task", 4 * 1024, NULL, 5, NULL); - // xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 5, &user_input_task); - - //meter_init(); - - // ocpp_start(); - - // serial_mdb_start(); - - currentshaper_start(); - - // initRc522(); - - // initWiegand(); - - serial_mt_start(); - - // master_sync_start(); - - // slave_sync_start(); - - xTaskCreate(evse_task_func, "evse_task", 20 * 1024, NULL, 5, &evse_task); - - app_start(); - - /* - while (true) - { - evse_process(); - update_leds(); - - // ESP_LOGI(TAG, "getPower %d", getDataMeter().wattA); - - vTaskDelay(pdMS_TO_TICKS(100)); - } - */ -} diff --git a/main_back2 b/main_back2 deleted file mode 100755 index 323110c..0000000 --- a/main_back2 +++ /dev/null @@ -1,348 +0,0 @@ - -#include -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "esp_ota_ops.h" -#include "esp_log.h" -#include "esp_err.h" -#include "nvs_flash.h" -#include "esp_event.h" -#include "esp_spiffs.h" -#include "driver/gpio.h" - -#include "evse_api.h" -#include "peripherals.h" -#include "led.h" -#include "api.h" -#include "protocols.h" -#include "serial_mt.h" -#include "board_config.h" -#include "wifi.h" -#include "logger.h" -// #include "ocpp.h" -// #include "currentshaper.h" -// #include "serial_mdb.h" -// #include "meter.h" -// #include "rc522_2.h" -// #include "main_wiegand.h" -// #include "app_main.h" - -// #include "sync_slave.h" -// #include "sync_master.h" -#define AP_CONNECTION_TIMEOUT 60000 // 60sec -#define RESET_HOLD_TIME 10000 // 10sec - -#define PRESS_BIT BIT0 -#define RELEASED_BIT BIT1 - -static const char *TAG = "app_main"; - -static TaskHandle_t user_input_task; - -static evse_state_t led_state = -1; - -static void reset_and_reboot(void) -{ - ESP_LOGW(TAG, "All settings will be erased..."); - ESP_ERROR_CHECK(nvs_flash_erase()); - - ESP_LOGW(TAG, "Rebooting..."); - vTaskDelay(pdMS_TO_TICKS(500)); - - esp_restart(); -} - -static void wifi_event_task_func(void *param) -{ - EventBits_t mode_bits; - - while (true) - { - // led_set_off(LED_ID_WIFI); - mode_bits = xEventGroupWaitBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); - if (mode_bits & WIFI_AP_MODE_BIT) - { - // led_set_state(LED_ID_WIFI, 100, 900); - - if (xEventGroupWaitBits(wifi_event_group, WIFI_AP_CONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & WIFI_AP_CONNECTED_BIT) - { - // led_set_state(LED_ID_WIFI, 1900, 100); - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_AP_DISCONNECTED_BIT)); - } - else - { - if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) - { - // serial_mdb_set_meter_test(false); - wifi_ap_stop(); - } - } - } - else if (mode_bits & WIFI_STA_MODE_BIT) - { - // led_set_state(LED_ID_WIFI, 500, 500); - - if (xEventGroupWaitBits(wifi_event_group, WIFI_STA_CONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_CONNECTED_BIT) - { - // led_set_on(LED_ID_WIFI); - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_DISCONNECTED_BIT)); - } - } - } -} - -static void user_input_task_func(void *param) -{ - uint32_t notification; - - bool pressed = false; - TickType_t press_tick = 0; - - while (true) - { - if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) - { - if (notification & PRESS_BIT) - { - press_tick = xTaskGetTickCount(); - pressed = true; - } - if (notification & RELEASED_BIT) - { - if (pressed) - { // sometimes after connect debug UART emit RELEASED_BIT without preceding PRESS_BIT - if (xTaskGetTickCount() - press_tick >= pdMS_TO_TICKS(RESET_HOLD_TIME)) - { - evse_set_available(false); - reset_and_reboot(); - } - else - { - if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) - { - led_set_buzzer(); - wifi_ap_start(); - // serial_mdb_set_meter_test(true); - } - } - } - pressed = false; - } - } - } -} - -static void IRAM_ATTR button_isr_handler(void *arg) -{ - BaseType_t higher_task_woken = pdFALSE; - - if (!gpio_get_level(board_config.button_wifi_gpio)) - { - xTaskNotifyFromISR(user_input_task, RELEASED_BIT, eSetBits, &higher_task_woken); - } - else - { - xTaskNotifyFromISR(user_input_task, PRESS_BIT, eSetBits, &higher_task_woken); - } - - if (higher_task_woken) - { - portYIELD_FROM_ISR(); - } -} - -static void button_init(void) -{ - gpio_config_t conf = { - .pin_bit_mask = BIT64(board_config.button_wifi_gpio), - .mode = GPIO_MODE_INPUT, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .pull_up_en = GPIO_PULLUP_ENABLE, - .intr_type = GPIO_INTR_ANYEDGE}; - ESP_ERROR_CHECK(gpio_config(&conf)); - ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); -} - -static void fs_info(esp_vfs_spiffs_conf_t *conf) -{ - size_t total = 0, used = 0; - esp_err_t ret = esp_spiffs_info(conf->partition_label, &total, &used); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to get partition %s information %s", conf->partition_label, esp_err_to_name(ret)); - } - else - { - ESP_LOGI(TAG, "Partition %s size: total: %d, used: %d", conf->partition_label, total, used); - } -} - -static void fs_init(void) -{ - esp_vfs_spiffs_conf_t cfg_conf = { - .base_path = "/cfg", - .partition_label = "cfg", - .max_files = 1, - .format_if_mount_failed = false}; - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&cfg_conf)); - - esp_vfs_spiffs_conf_t data_conf = { - .base_path = "/data", - .partition_label = "data", - .max_files = 5, - .format_if_mount_failed = true}; - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&data_conf)); - - fs_info(&cfg_conf); - fs_info(&data_conf); -} - -static bool ota_diagnostic(void) -{ - // TODO diagnostic after ota - return true; -} - -static void update_leds(void) -{ - if (led_state != evse_get_state()) - { - led_state = evse_get_state(); - - switch (led_state) - { - case EVSE_STATE_A: - led_set_off(LED_ID_CHARGING); - led_set_off(LED_ID_ERROR); - led_set_on(LED_ID_WIFI); - break; - case EVSE_STATE_B1: - case EVSE_STATE_B2: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_on(LED_ID_CHARGING); - break; - case EVSE_STATE_C1: - case EVSE_STATE_D1: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_CHARGING, 1000, 1000); - break; - case EVSE_STATE_C2: - case EVSE_STATE_D2: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_CHARGING, 1000, 500); - led_set_buzzer(); - break; - case EVSE_STATE_E: - led_set_off(LED_ID_WIFI); - led_set_off(LED_ID_CHARGING); - led_set_state(LED_ID_ERROR, 500, 500); - break; - case EVSE_STATE_F: - led_set_off(LED_ID_CHARGING); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_ERROR, 500, 500); - break; - } - } -} - -void app_main(void) -{ - - logger_init(); - esp_log_set_vprintf(logger_vprintf); - - const esp_partition_t *running = esp_ota_get_running_partition(); - ESP_LOGI(TAG, "Running partition: %s", running->label); - - esp_ota_img_states_t ota_state; - if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) - { - if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) - { - ESP_LOGI(TAG, "OTA pending verify"); - if (ota_diagnostic()) - { - ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ..."); - esp_ota_mark_app_valid_cancel_rollback(); - } - else - { - ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ..."); - esp_ota_mark_app_invalid_rollback_and_reboot(); - } - } - } - - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_LOGW(TAG, "Erasing NVS flash"); - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - fs_init(); - - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - ESP_ERROR_CHECK(gpio_install_isr_service(0)); - - board_config_load(); - - wifi_ini(); - - peripherals_init(); - - api_init(); - - protocols_init(); - - evse_init(); - - button_init(); - - xTaskCreate(wifi_event_task_func, "wifi_event_task", 4 * 1024, NULL, 5, NULL); - xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 5, &user_input_task); - - // meter_init(); - - // ocpp_start(); - - // serial_mdb_start(); - - // currentshaper_start(); - - // initRc522(); - - // initWiegand(); - - // serial_mt_start(); - - // master_sync_start(); - - // slave_sync_start(); - - while (true) - { - evse_process(); - update_leds(); - - // ESP_LOGI(TAG, "getPower %d", getDataMeter().wattA); - - vTaskDelay(pdMS_TO_TICKS(100)); - } -} diff --git a/main_back3 b/main_back3 deleted file mode 100755 index ea59eb0..0000000 --- a/main_back3 +++ /dev/null @@ -1,346 +0,0 @@ - -#include -#include -#include -#include "sdkconfig.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "esp_ota_ops.h" -#include "esp_log.h" -#include "esp_err.h" -#include "nvs_flash.h" -#include "esp_event.h" -#include "esp_spiffs.h" -#include "driver/gpio.h" - -#include "evse_api.h" -#include "peripherals.h" -#include "led.h" -#include "api.h" -#include "protocols.h" -#include "serial_mt.h" -#include "board_config.h" -#include "wifi.h" -#include "logger.h" -// #include "ocpp.h" -// #include "currentshaper.h" -// #include "serial_mdb.h" -// #include "meter.h" -// #include "rc522_2.h" -// #include "main_wiegand.h" -// #include "app_main.h" - -// #include "sync_slave.h" -// #include "sync_master.h" -#define AP_CONNECTION_TIMEOUT 60000 // 60sec -#define RESET_HOLD_TIME 10000 // 10sec - -#define PRESS_BIT BIT0 -#define RELEASED_BIT BIT1 - -static const char *TAG = "app_main"; - -static TaskHandle_t user_input_task; - -static evse_state_t led_state = -1; - -static void reset_and_reboot(void) -{ - ESP_LOGW(TAG, "All settings will be erased..."); - ESP_ERROR_CHECK(nvs_flash_erase()); - - ESP_LOGW(TAG, "Rebooting..."); - vTaskDelay(pdMS_TO_TICKS(500)); - - esp_restart(); -} - -static void wifi_event_task_func(void *param) -{ - EventBits_t mode_bits; - - while (true) - { - // led_set_off(LED_ID_WIFI); - mode_bits = xEventGroupWaitBits(wifi_event_group, WIFI_AP_MODE_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY); - if (mode_bits & WIFI_AP_MODE_BIT) - { - // led_set_state(LED_ID_WIFI, 100, 900); - - if (xEventGroupWaitBits(wifi_event_group, WIFI_AP_CONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(AP_CONNECTION_TIMEOUT)) & WIFI_AP_CONNECTED_BIT) - { - // led_set_state(LED_ID_WIFI, 1900, 100); - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_AP_DISCONNECTED_BIT | WIFI_STA_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_AP_DISCONNECTED_BIT)); - } - else - { - if (xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT) - { - // serial_mdb_set_meter_test(false); - wifi_ap_stop(); - } - } - } - else if (mode_bits & WIFI_STA_MODE_BIT) - { - // led_set_state(LED_ID_WIFI, 500, 500); - - if (xEventGroupWaitBits(wifi_event_group, WIFI_STA_CONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_CONNECTED_BIT) - { - // led_set_on(LED_ID_WIFI); - do - { - } while (!(xEventGroupWaitBits(wifi_event_group, WIFI_STA_DISCONNECTED_BIT | WIFI_AP_MODE_BIT, pdFALSE, pdFALSE, portMAX_DELAY) & WIFI_STA_DISCONNECTED_BIT)); - } - } - } -} - -static void user_input_task_func(void *param) -{ - uint32_t notification; - - bool pressed = false; - TickType_t press_tick = 0; - - while (true) - { - if (xTaskNotifyWait(0x00, 0xff, ¬ification, portMAX_DELAY)) - { - if (notification & PRESS_BIT) - { - press_tick = xTaskGetTickCount(); - pressed = true; - } - if (notification & RELEASED_BIT) - { - if (pressed) - { // sometimes after connect debug UART emit RELEASED_BIT without preceding PRESS_BIT - if (xTaskGetTickCount() - press_tick >= pdMS_TO_TICKS(RESET_HOLD_TIME)) - { - evse_set_available(false); - reset_and_reboot(); - } - else - { - if (!(xEventGroupGetBits(wifi_event_group) & WIFI_AP_MODE_BIT)) - { - wifi_ap_start(); - // serial_mdb_set_meter_test(true); - } - } - } - pressed = false; - } - } - } -} - -static void IRAM_ATTR button_isr_handler(void *arg) -{ - BaseType_t higher_task_woken = pdFALSE; - - if (!gpio_get_level(board_config.button_wifi_gpio)) - { - xTaskNotifyFromISR(user_input_task, RELEASED_BIT, eSetBits, &higher_task_woken); - } - else - { - xTaskNotifyFromISR(user_input_task, PRESS_BIT, eSetBits, &higher_task_woken); - } - - if (higher_task_woken) - { - portYIELD_FROM_ISR(); - } -} - -static void button_init(void) -{ - gpio_config_t conf = { - .pin_bit_mask = BIT64(board_config.button_wifi_gpio), - .mode = GPIO_MODE_INPUT, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .pull_up_en = GPIO_PULLUP_ENABLE, - .intr_type = GPIO_INTR_ANYEDGE}; - ESP_ERROR_CHECK(gpio_config(&conf)); - ESP_ERROR_CHECK(gpio_isr_handler_add(board_config.button_wifi_gpio, button_isr_handler, NULL)); -} - -static void fs_info(esp_vfs_spiffs_conf_t *conf) -{ - size_t total = 0, used = 0; - esp_err_t ret = esp_spiffs_info(conf->partition_label, &total, &used); - if (ret != ESP_OK) - { - ESP_LOGE(TAG, "Failed to get partition %s information %s", conf->partition_label, esp_err_to_name(ret)); - } - else - { - ESP_LOGI(TAG, "Partition %s size: total: %d, used: %d", conf->partition_label, total, used); - } -} - -static void fs_init(void) -{ - esp_vfs_spiffs_conf_t cfg_conf = { - .base_path = "/cfg", - .partition_label = "cfg", - .max_files = 1, - .format_if_mount_failed = false}; - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&cfg_conf)); - - esp_vfs_spiffs_conf_t data_conf = { - .base_path = "/data", - .partition_label = "data", - .max_files = 5, - .format_if_mount_failed = true}; - ESP_ERROR_CHECK(esp_vfs_spiffs_register(&data_conf)); - - fs_info(&cfg_conf); - fs_info(&data_conf); -} - -static bool ota_diagnostic(void) -{ - // TODO diagnostic after ota - return true; -} - -static void update_leds(void) -{ - if (led_state != evse_get_state()) - { - led_state = evse_get_state(); - - switch (led_state) - { - case EVSE_STATE_A: - led_set_off(LED_ID_CHARGING); - led_set_off(LED_ID_ERROR); - led_set_on(LED_ID_WIFI); - break; - case EVSE_STATE_B1: - case EVSE_STATE_B2: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_on(LED_ID_CHARGING); - break; - case EVSE_STATE_C1: - case EVSE_STATE_D1: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - break; - case EVSE_STATE_C2: - case EVSE_STATE_D2: - led_set_off(LED_ID_ERROR); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_CHARGING, 1000, 500); - led_set_buzzer(); - break; - case EVSE_STATE_E: - led_set_off(LED_ID_WIFI); - led_set_off(LED_ID_CHARGING); - led_set_state(LED_ID_ERROR, 500, 500); - break; - case EVSE_STATE_F: - led_set_off(LED_ID_CHARGING); - led_set_off(LED_ID_WIFI); - led_set_state(LED_ID_ERROR, 500, 500); - break; - } - } -} - -void app_main(void) -{ - - logger_init(); - esp_log_set_vprintf(logger_vprintf); - - const esp_partition_t *running = esp_ota_get_running_partition(); - ESP_LOGI(TAG, "Running partition: %s", running->label); - - esp_ota_img_states_t ota_state; - if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) - { - if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) - { - ESP_LOGI(TAG, "OTA pending verify"); - if (ota_diagnostic()) - { - ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution ..."); - esp_ota_mark_app_valid_cancel_rollback(); - } - else - { - ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version ..."); - esp_ota_mark_app_invalid_rollback_and_reboot(); - } - } - } - - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) - { - ESP_LOGW(TAG, "Erasing NVS flash"); - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - fs_init(); - - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - - ESP_ERROR_CHECK(gpio_install_isr_service(0)); - - board_config_load(); - - wifi_ini(); - - peripherals_init(); - - api_init(); - - protocols_init(); - - evse_init(); - - button_init(); - - xTaskCreate(wifi_event_task_func, "wifi_event_task", 4 * 1024, NULL, 5, NULL); - xTaskCreate(user_input_task_func, "user_input_task", 4 * 1024, NULL, 5, &user_input_task); - - // meter_init(); - - // ocpp_start(); - - // serial_mdb_start(); - - // currentshaper_start(); - - // initRc522(); - - // initWiegand(); - - // serial_mt_start(); - - // master_sync_start(); - - // slave_sync_start(); - - while (true) - { - evse_process(); - update_leds(); - - // ESP_LOGI(TAG, "getPower %d", getDataMeter().wattA); - - vTaskDelay(pdMS_TO_TICKS(100)); - } -} diff --git a/managed_components/espressif__cmake_utilities/.component_hash b/managed_components/espressif__cmake_utilities/.component_hash old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/CHANGELOG.md b/managed_components/espressif__cmake_utilities/CHANGELOG.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/CMakeLists.txt b/managed_components/espressif__cmake_utilities/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/Kconfig b/managed_components/espressif__cmake_utilities/Kconfig old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/README.md b/managed_components/espressif__cmake_utilities/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/cmake_utilities.cmake b/managed_components/espressif__cmake_utilities/cmake_utilities.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/docs/gcc.md b/managed_components/espressif__cmake_utilities/docs/gcc.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md b/managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/docs/relinker.md b/managed_components/espressif__cmake_utilities/docs/relinker.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/gcc.cmake b/managed_components/espressif__cmake_utilities/gcc.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake b/managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/gen_single_bin.cmake b/managed_components/espressif__cmake_utilities/gen_single_bin.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/idf_component.yml b/managed_components/espressif__cmake_utilities/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/license.txt b/managed_components/espressif__cmake_utilities/license.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/package_manager.cmake b/managed_components/espressif__cmake_utilities/package_manager.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/project_include.cmake b/managed_components/espressif__cmake_utilities/project_include.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/relinker.cmake b/managed_components/espressif__cmake_utilities/relinker.cmake old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/scripts/gen_custom_ota.py b/managed_components/espressif__cmake_utilities/scripts/gen_custom_ota.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/configuration.py b/managed_components/espressif__cmake_utilities/scripts/relinker/configuration.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/function.csv b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/function.csv old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/library.csv b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/library.csv old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/object.csv b/managed_components/espressif__cmake_utilities/scripts/relinker/examples/esp32c2/object.csv old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/scripts/relinker/relinker.py b/managed_components/espressif__cmake_utilities/scripts/relinker/relinker.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/idf_component.yml b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.c b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.h b/managed_components/espressif__cmake_utilities/test_apps/components/TEST-component2/test_component2.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/idf_component.yml b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.c b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.h b/managed_components/espressif__cmake_utilities/test_apps/components/test_component1/test_component1.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/main/CMakeLists.txt b/managed_components/espressif__cmake_utilities/test_apps/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/main/test_cmake_utilities.c b/managed_components/espressif__cmake_utilities/test_apps/main/test_cmake_utilities.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__cmake_utilities/test_apps/pytest_cmake_utilities.py b/managed_components/espressif__cmake_utilities/test_apps/pytest_cmake_utilities.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/.component_hash b/managed_components/espressif__mdns/.component_hash old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/.cz.yaml b/managed_components/espressif__mdns/.cz.yaml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/CHANGELOG.md b/managed_components/espressif__mdns/CHANGELOG.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/CMakeLists.txt b/managed_components/espressif__mdns/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/Kconfig b/managed_components/espressif__mdns/Kconfig old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/LICENSE b/managed_components/espressif__mdns/LICENSE old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/README.md b/managed_components/espressif__mdns/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/CMakeLists.txt b/managed_components/espressif__mdns/examples/query_advertise/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/README.md b/managed_components/espressif__mdns/examples/query_advertise/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/CMakeLists.txt b/managed_components/espressif__mdns/examples/query_advertise/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/Kconfig.projbuild b/managed_components/espressif__mdns/examples/query_advertise/main/Kconfig.projbuild old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/idf_component.yml b/managed_components/espressif__mdns/examples/query_advertise/main/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/main/mdns_example_main.c b/managed_components/espressif__mdns/examples/query_advertise/main/mdns_example_main.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/examples/query_advertise/pytest_mdns.py b/managed_components/espressif__mdns/examples/query_advertise/pytest_mdns.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/idf_component.yml b/managed_components/espressif__mdns/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/include/mdns.h b/managed_components/espressif__mdns/include/mdns.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/include/mdns_console.h b/managed_components/espressif__mdns/include/mdns_console.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/mdns.c b/managed_components/espressif__mdns/mdns.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/mdns_console.c b/managed_components/espressif__mdns/mdns_console.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/mdns_mem_caps.c b/managed_components/espressif__mdns/mdns_mem_caps.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/mdns_networking_lwip.c b/managed_components/espressif__mdns/mdns_networking_lwip.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/mdns_networking_socket.c b/managed_components/espressif__mdns/mdns_networking_socket.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/mem_prefix_script.py b/managed_components/espressif__mdns/mem_prefix_script.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/private_include/mdns_mem_caps.h b/managed_components/espressif__mdns/private_include/mdns_mem_caps.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/private_include/mdns_networking.h b/managed_components/espressif__mdns/private_include/mdns_networking.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/private_include/mdns_private.h b/managed_components/espressif__mdns/private_include/mdns_private.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/CMakeLists.txt b/managed_components/espressif__mdns/tests/host_test/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/README.md b/managed_components/espressif__mdns/tests/host_test/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/CMakeLists.txt b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/Kconfig b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/Kconfig old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/esp_netif_linux.c b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/esp_netif_linux.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/esp_wifi_types.h b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/esp_wifi_types.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/machine/endian.h b/managed_components/espressif__mdns/tests/host_test/components/esp_netif_linux/include/machine/endian.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/dnsfixture.py b/managed_components/espressif__mdns/tests/host_test/dnsfixture.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/main/CMakeLists.txt b/managed_components/espressif__mdns/tests/host_test/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/main/Kconfig.projbuild b/managed_components/espressif__mdns/tests/host_test/main/Kconfig.projbuild old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/main/idf_component.yml b/managed_components/espressif__mdns/tests/host_test/main/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/main/main.c b/managed_components/espressif__mdns/tests/host_test/main/main.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/host_test/pytest_mdns.py b/managed_components/espressif__mdns/tests/host_test/pytest_mdns.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/CMakeLists.txt b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/README.md b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.c b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp32_mock.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_attr.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_attr.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_netif_mock.c b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/esp_netif_mock.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/file2.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/file2.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_4a_txt.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_4a_txt.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_aaaa.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_aaaa.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_any.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_any.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_disc.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_disc.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_ptr.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_ptr.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query2.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/minif_query2.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/sub_fritz_m.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/sub_fritz_m.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/telnet_ptr.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/telnet_ptr.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-14.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-14.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-15.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-15.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-16.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-16.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-28.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-28.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-29.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-29.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-31.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-31.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-53.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-53.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-56.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-56.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-63.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-63.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-83.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-83.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-88.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-88.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-89.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-89.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-95.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-95.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-96.bin b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/in/test-96.bin old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/input_packets.txt b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/input_packets.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_di.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_di.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_mock.h b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/mdns_mock.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_afl_fuzz_host/test.c b/managed_components/espressif__mdns/tests/test_afl_fuzz_host/test.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/CMakeLists.txt b/managed_components/espressif__mdns/tests/test_apps/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/README.md b/managed_components/espressif__mdns/tests/test_apps/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/main/CMakeLists.txt b/managed_components/espressif__mdns/tests/test_apps/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/main/Kconfig.projbuild b/managed_components/espressif__mdns/tests/test_apps/main/Kconfig.projbuild old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/main/idf_component.yml b/managed_components/espressif__mdns/tests/test_apps/main/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/main/main.c b/managed_components/espressif__mdns/tests/test_apps/main/main.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/main/mdns_test.c b/managed_components/espressif__mdns/tests/test_apps/main/mdns_test.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/test_apps/pytest_mdns_app.py b/managed_components/espressif__mdns/tests/test_apps/pytest_mdns_app.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/unit_test/CMakeLists.txt b/managed_components/espressif__mdns/tests/unit_test/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/unit_test/main/CMakeLists.txt b/managed_components/espressif__mdns/tests/unit_test/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/unit_test/main/test_mdns.c b/managed_components/espressif__mdns/tests/unit_test/main/test_mdns.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__mdns/tests/unit_test/pytest_app_mdns.py b/managed_components/espressif__mdns/tests/unit_test/pytest_app_mdns.py old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/.component_hash b/managed_components/espressif__ntc_driver/.component_hash old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/CHANGELOG.md b/managed_components/espressif__ntc_driver/CHANGELOG.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/CMakeLists.txt b/managed_components/espressif__ntc_driver/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/README.md b/managed_components/espressif__ntc_driver/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/README_CN.md b/managed_components/espressif__ntc_driver/README_CN.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/CMakeLists.txt b/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/README.md b/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/README.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/README_CN.md b/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/README_CN.md old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/main/CMakeLists.txt b/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/main/idf_component.yml b/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/main/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/main/ntc_temperature_example_main.c b/managed_components/espressif__ntc_driver/examples/ntc_temperature_sensor/main/ntc_temperature_example_main.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/idf_component.yml b/managed_components/espressif__ntc_driver/idf_component.yml old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/include/ntc_driver.h b/managed_components/espressif__ntc_driver/include/ntc_driver.h old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/license.txt b/managed_components/espressif__ntc_driver/license.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/ntc_driver.c b/managed_components/espressif__ntc_driver/ntc_driver.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/test_apps/CMakeLists.txt b/managed_components/espressif__ntc_driver/test_apps/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/test_apps/main/CMakeLists.txt b/managed_components/espressif__ntc_driver/test_apps/main/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/test_apps/main/test_ntc_driver.c b/managed_components/espressif__ntc_driver/test_apps/main/test_ntc_driver.c old mode 100755 new mode 100644 diff --git a/managed_components/espressif__ntc_driver/test_apps/pytest_ntc_driver.py b/managed_components/espressif__ntc_driver/test_apps/pytest_ntc_driver.py old mode 100755 new mode 100644 diff --git a/partitions.csv b/partitions.csv index c6aa194..e867783 100755 --- a/partitions.csv +++ b/partitions.csv @@ -1,8 +1,7 @@ -# Name, Type, SubType, Offset, Size, Flags +# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x4000, -otadata, data, ota, 0xd000, 0x2000, -phy_init, data, phy, 0xf000, 0x1000, -factory, app, factory, 0x10000, 3500k, -fctry, data, nvs, , 0x6000 -cfg, data, spiffs, , 16K, -data, data, spiffs, , 304K, \ No newline at end of file +phy_init, data, phy, 0xd000, 0x1000, +factory, app, factory, 0x10000, 3500K, +fctry, data, nvs, , 0x6000 +cfg, data, spiffs, , 16K, +data, data, spiffs, , 304K,