new meter
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user