new meter
This commit is contained in:
@@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp32-evse)
|
||||
project(chargeflow)
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -3,68 +3,80 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
#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
|
||||
|
||||
21
components/auth/include/auth_events.h
Normal file
21
components/auth/include/auth_events.h
Normal file
@@ -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;
|
||||
@@ -3,26 +3,25 @@
|
||||
*/
|
||||
|
||||
#include "auth.h"
|
||||
#include "auth_events.h"
|
||||
#include "esp_event.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
3
components/auth/src/auth_events.c
Normal file
3
components/auth/src/auth_events.c
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "auth_events.h"
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(AUTH_EVENTS);
|
||||
@@ -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;
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
/*
|
||||
* wiegand_reader.c
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
@@ -10,8 +5,6 @@
|
||||
#include <freertos/queue.h>
|
||||
#include <esp_log.h>
|
||||
#include <wiegand.h>
|
||||
#include <evse_api.h>
|
||||
#include <ocpp.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <inttypes.h> // Include for PRI macros
|
||||
|
||||
#include <inttypes.h> // 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
// ================================
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#include "evse_events.h"
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(EVSE_EVENT);
|
||||
ESP_EVENT_DEFINE_BASE(EVSE_EVENTS);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <string.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "pilot.h"
|
||||
#include "evse_pilot.h"
|
||||
|
||||
|
||||
#define EVSE_ERR_AUTO_CLEAR_BITS ( \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "evse_api.h"
|
||||
#include "pilot.h"
|
||||
#include "evse_pilot.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
#ifndef EVSE_MANAGER_H
|
||||
#define EVSE_MANAGER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#ifndef EVSE_STATE_H
|
||||
#define EVSE_STATE_H
|
||||
|
||||
#include "evse_events.h"
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -5,13 +5,75 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#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
|
||||
}
|
||||
|
||||
24
components/loadbalancer/include/loadbalancer_events.h
Normal file
24
components/loadbalancer/include/loadbalancer_events.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "esp_event.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
|
||||
@@ -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 <string.h> // Para memcpy
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include <string.h>
|
||||
#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));
|
||||
}
|
||||
|
||||
4
components/loadbalancer/src/loadbalancer_events.c
Normal file
4
components/loadbalancer/src/loadbalancer_events.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "loadbalancer_events.h"
|
||||
|
||||
// Define a base de eventos para o loadbalancer
|
||||
ESP_EVENT_DEFINE_BASE(LOADBALANCER_EVENTS);
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "meter_ade7758.h"
|
||||
#include "ade7758.h"
|
||||
#include "meter_events.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 <stddef.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 <stddef.h>
|
||||
|
||||
#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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 <stdint.h>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
38
components/meter_manager/include/meter_events.h
Normal file
38
components/meter_manager/include/meter_events.h
Normal file
@@ -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
|
||||
@@ -2,28 +2,66 @@
|
||||
#define METER_MANAGER_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include <stdbool.h> // 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
|
||||
|
||||
4
components/meter_manager/src/meter_events.c
Normal file
4
components/meter_manager/src/meter_events.c
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "meter_events.h"
|
||||
|
||||
// Define a base de eventos
|
||||
ESP_EVENT_DEFINE_BASE(METER_EVENT);
|
||||
@@ -4,135 +4,196 @@
|
||||
#include "meter_orno513.h"
|
||||
#include "meter_orno516.h"
|
||||
#include "meter_zigbee.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include <string.h>
|
||||
|
||||
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
|
||||
|
||||
143
components/network/src/wifi_2.c
Normal file
143
components/network/src/wifi_2.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <string.h>
|
||||
#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 <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
24
components/rest_api/CMakeLists.txt
Executable file
24
components/rest_api/CMakeLists.txt
Executable file
@@ -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()
|
||||
16
components/rest_api/include/auth_api.h
Executable file
16
components/rest_api/include/auth_api.h
Executable file
@@ -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
|
||||
16
components/rest_api/include/dashboard_api.h
Normal file
16
components/rest_api/include/dashboard_api.h
Normal file
@@ -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
|
||||
16
components/rest_api/include/evse_settings_api.h
Executable file
16
components/rest_api/include/evse_settings_api.h
Executable file
@@ -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
|
||||
14
components/rest_api/include/loadbalancing_settings_api.h
Normal file
14
components/rest_api/include/loadbalancing_settings_api.h
Normal file
@@ -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
|
||||
14
components/rest_api/include/meters_settings_api.h
Normal file
14
components/rest_api/include/meters_settings_api.h
Normal file
@@ -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
|
||||
16
components/rest_api/include/network_api.h
Executable file
16
components/rest_api/include/network_api.h
Executable file
@@ -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
|
||||
16
components/rest_api/include/ocpp_api.h
Executable file
16
components/rest_api/include/ocpp_api.h
Executable file
@@ -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
|
||||
13
components/rest_api/include/rest_main.h
Executable file
13
components/rest_api/include/rest_main.h
Executable file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <esp_err.h>
|
||||
#include <esp_vfs.h>
|
||||
|
||||
#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);
|
||||
16
components/rest_api/include/static_file_api.h
Normal file
16
components/rest_api/include/static_file_api.h
Normal file
@@ -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
|
||||
141
components/rest_api/src/auth_api.c
Executable file
141
components/rest_api/src/auth_api.c
Executable file
@@ -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
|
||||
});
|
||||
}
|
||||
83
components/rest_api/src/dashboard_api.c
Normal file
83
components/rest_api/src/dashboard_api.c
Normal file
@@ -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);
|
||||
}
|
||||
63
components/rest_api/src/evse_settings_api.c
Executable file
63
components/rest_api/src/evse_settings_api.c
Executable file
@@ -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);
|
||||
}
|
||||
108
components/rest_api/src/loadbalancing_settings_api.c
Normal file
108
components/rest_api/src/loadbalancing_settings_api.c
Normal file
@@ -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);
|
||||
}
|
||||
111
components/rest_api/src/meters_settings_api.c
Normal file
111
components/rest_api/src/meters_settings_api.c
Normal file
@@ -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);
|
||||
}
|
||||
257
components/rest_api/src/network_api.c
Executable file
257
components/rest_api/src/network_api.c
Executable file
@@ -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);
|
||||
}
|
||||
92
components/rest_api/src/ocpp_api.c
Executable file
92
components/rest_api/src/ocpp_api.c
Executable file
@@ -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);
|
||||
}
|
||||
53
components/rest_api/src/rest_main.c
Executable file
53
components/rest_api/src/rest_main.c
Executable file
@@ -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;
|
||||
}
|
||||
89
components/rest_api/src/static_file_api.c
Normal file
89
components/rest_api/src/static_file_api.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "static_file_api.h"
|
||||
#include "esp_log.h"
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include "esp_vfs.h"
|
||||
|
||||
static const char *TAG = "static_file_api";
|
||||
|
||||
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
|
||||
#define SCRATCH_BUFSIZE (10240)
|
||||
|
||||
typedef struct rest_server_context {
|
||||
char base_path[ESP_VFS_PATH_MAX + 1];
|
||||
char scratch[SCRATCH_BUFSIZE];
|
||||
} rest_server_context_t;
|
||||
|
||||
#define CHECK_FILE_EXTENSION(filename, ext) \
|
||||
(strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
|
||||
|
||||
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath) {
|
||||
const char *type = "text/plain";
|
||||
if (CHECK_FILE_EXTENSION(filepath, ".html")) type = "text/html";
|
||||
else if (CHECK_FILE_EXTENSION(filepath, ".js")) type = "application/javascript";
|
||||
else if (CHECK_FILE_EXTENSION(filepath, ".css")) type = "text/css";
|
||||
else if (CHECK_FILE_EXTENSION(filepath, ".png")) type = "image/png";
|
||||
else if (CHECK_FILE_EXTENSION(filepath, ".ico")) type = "image/x-icon";
|
||||
else if (CHECK_FILE_EXTENSION(filepath, ".svg")) type = "image/svg+xml";
|
||||
return httpd_resp_set_type(req, type);
|
||||
}
|
||||
|
||||
static esp_err_t static_get_handler(httpd_req_t *req) {
|
||||
char filepath[FILE_PATH_MAX];
|
||||
rest_server_context_t *ctx = (rest_server_context_t *) req->user_ctx;
|
||||
|
||||
strlcpy(filepath, ctx->base_path, sizeof(filepath));
|
||||
if (req->uri[strlen(req->uri) - 1] == '/') {
|
||||
strlcat(filepath, "/index.html", sizeof(filepath));
|
||||
} else {
|
||||
strlcat(filepath, req->uri, sizeof(filepath));
|
||||
}
|
||||
|
||||
int fd = open(filepath, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
// fallback para /index.html (SPA)
|
||||
ESP_LOGW(TAG, "Arquivo não encontrado: %s. Tentando index.html", filepath);
|
||||
strlcpy(filepath, ctx->base_path, sizeof(filepath));
|
||||
strlcat(filepath, "/index.html", sizeof(filepath));
|
||||
fd = open(filepath, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Arquivo não encontrado");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
set_content_type_from_file(req, filepath);
|
||||
|
||||
char *chunk = ctx->scratch;
|
||||
ssize_t read_bytes;
|
||||
do {
|
||||
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
|
||||
if (read_bytes == -1) {
|
||||
ESP_LOGE(TAG, "Erro lendo arquivo: %s", filepath);
|
||||
close(fd);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao ler arquivo");
|
||||
return ESP_FAIL;
|
||||
} else if (read_bytes > 0) {
|
||||
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
|
||||
close(fd);
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao enviar arquivo");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
} while (read_bytes > 0);
|
||||
|
||||
close(fd);
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void register_static_file_handlers(httpd_handle_t server, void *ctx) {
|
||||
httpd_uri_t uri = {
|
||||
.uri = "/*",
|
||||
.method = HTTP_GET,
|
||||
.handler = static_get_handler,
|
||||
.user_ctx = ctx
|
||||
};
|
||||
httpd_register_uri_handler(server, &uri);
|
||||
}
|
||||
1
components/rest_api/webfolder/assets/index-DvcKJk-E.css
Normal file
1
components/rest_api/webfolder/assets/index-DvcKJk-E.css
Normal file
File diff suppressed because one or more lines are too long
51
components/rest_api/webfolder/assets/index-zZ02wEhQ.js
Normal file
51
components/rest_api/webfolder/assets/index-zZ02wEhQ.js
Normal file
File diff suppressed because one or more lines are too long
23
components/rest_api/webfolder/index.html
Normal file
23
components/rest_api/webfolder/index.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<!-- <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> -->
|
||||
<!-- Remover link para tailwind.min.css -->
|
||||
<!-- <link href="/tailwind.min.css" rel="stylesheet"> -->
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', 'Helvetica', 'sans-serif'; /* Usando fontes genéricas do sistema */
|
||||
}
|
||||
</style>
|
||||
<title>Vite + React</title>
|
||||
<script type="module" crossorigin src="/assets/index-zZ02wEhQ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DvcKJk-E.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!-- Adicionar o link para o seu arquivo CSS com o Tailwind configurado -->
|
||||
</body>
|
||||
</html>
|
||||
1
components/rest_api/webfolder/vite.svg
Executable file
1
components/rest_api/webfolder/vite.svg
Executable file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
351
main/main.c
351
main/main.c
@@ -1,237 +1,181 @@
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#include "sdkconfig.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
375
main_back
375
main_back
@@ -1,375 +0,0 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#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));
|
||||
}
|
||||
*/
|
||||
}
|
||||
348
main_back2
348
main_back2
@@ -1,348 +0,0 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#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));
|
||||
}
|
||||
}
|
||||
346
main_back3
346
main_back3
@@ -1,346 +0,0 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/param.h>
|
||||
#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));
|
||||
}
|
||||
}
|
||||
0
managed_components/espressif__cmake_utilities/.component_hash
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/.component_hash
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/CHANGELOG.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/CHANGELOG.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/CMakeLists.txt
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/CMakeLists.txt
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/Kconfig
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/Kconfig
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/README.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/README.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/cmake_utilities.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/cmake_utilities.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/docs/gcc.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/docs/gcc.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/docs/gen_compressed_ota.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/docs/relinker.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/docs/relinker.md
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/gcc.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/gcc.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/gen_compressed_ota.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/gen_single_bin.cmake
Executable file → Normal file
0
managed_components/espressif__cmake_utilities/gen_single_bin.cmake
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user