new upgrade
This commit is contained in:
@@ -1,34 +1,123 @@
|
||||
#include <inttypes.h> // for PRIu32
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "evse_state.h"
|
||||
#include "evse_api.h"
|
||||
#include "evse_limits.h"
|
||||
#include "evse_meter.h"
|
||||
#include "evse_session.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_err.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
// ========================
|
||||
// Concurrency protection
|
||||
// ========================
|
||||
#include "storage_service.h"
|
||||
|
||||
#define NVS_NAMESPACE "evse_limits"
|
||||
static const char *TAG = "evse_limits";
|
||||
|
||||
static portMUX_TYPE evse_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
// ========================
|
||||
// Runtime state (volatile)
|
||||
// ========================
|
||||
static bool limit_reached = false;
|
||||
static uint32_t consumption_limit = 0; // Wh
|
||||
static uint32_t charging_time_limit = 0; // seconds
|
||||
static uint16_t under_power_limit = 0; // W
|
||||
|
||||
static bool limit_reached = false;
|
||||
static uint32_t consumption_limit = 0; // Energy limit in Wh
|
||||
static uint32_t charging_time_limit = 0; // Time limit in seconds
|
||||
static uint16_t under_power_limit = 0; // Minimum acceptable power in W
|
||||
static inline TickType_t TO_TICKS_MS(uint32_t ms) { return pdMS_TO_TICKS(ms); }
|
||||
static inline TickType_t BOOT_TO(void) { return TO_TICKS_MS(1000); }
|
||||
|
||||
// ========================
|
||||
// Limit status flag
|
||||
// ========================
|
||||
// ---------------------------------
|
||||
// Init + defaults
|
||||
// ---------------------------------
|
||||
esp_err_t evse_limits_init(void)
|
||||
{
|
||||
ESP_RETURN_ON_ERROR(storage_service_init(), TAG, "storage init failed");
|
||||
ESP_LOGI(TAG, "EVSE limits init OK (storage-backed)");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void evse_limits_check_defaults(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
bool needs_flush = false;
|
||||
|
||||
uint32_t u32 = 0;
|
||||
uint16_t u16 = 0;
|
||||
|
||||
ESP_LOGD(TAG, "Checking default limits...");
|
||||
|
||||
// Consumption limit (Wh) default = 0 (disabled)
|
||||
err = storage_get_u32_sync(NVS_NAMESPACE, "def_cons_lim", &u32, BOOT_TO());
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
consumption_limit = u32;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
}
|
||||
else
|
||||
{
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
consumption_limit = 0;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
|
||||
(void)storage_set_u32_async(NVS_NAMESPACE, "def_cons_lim", 0);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing def_cons_lim (%s) -> default=0 (persisted).", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Charging time limit (s) default = 0 (disabled)
|
||||
err = storage_get_u32_sync(NVS_NAMESPACE, "def_ch_time_lim", &u32, BOOT_TO());
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
charging_time_limit = u32;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
}
|
||||
else
|
||||
{
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
charging_time_limit = 0;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
|
||||
(void)storage_set_u32_async(NVS_NAMESPACE, "def_ch_time_lim", 0);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing def_ch_time_lim (%s) -> default=0 (persisted).", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// Under-power limit (W) default = 0 (disabled)
|
||||
err = storage_get_u16_sync(NVS_NAMESPACE, "def_un_pwr_lim", &u16, BOOT_TO());
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
under_power_limit = u16;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
}
|
||||
else
|
||||
{
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
under_power_limit = 0;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, "def_un_pwr_lim", 0);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing def_un_pwr_lim (%s) -> default=0 (persisted).", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
if (needs_flush)
|
||||
{
|
||||
esp_err_t fe = storage_flush_sync(TO_TICKS_MS(2000));
|
||||
if (fe != ESP_OK)
|
||||
ESP_LOGE(TAG, "storage_flush_sync failed: %s", esp_err_to_name(fe));
|
||||
else
|
||||
ESP_LOGD(TAG, "Defaults committed (flush).");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// Limit reached flag
|
||||
// ---------------------------------
|
||||
bool evse_get_limit_reached(void)
|
||||
{
|
||||
bool val;
|
||||
@@ -50,10 +139,9 @@ bool evse_is_limit_reached(void)
|
||||
return evse_get_limit_reached();
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Runtime limit accessors
|
||||
// ========================
|
||||
|
||||
// ---------------------------------
|
||||
// Consumption limit
|
||||
// ---------------------------------
|
||||
uint32_t evse_get_consumption_limit(void)
|
||||
{
|
||||
uint32_t val;
|
||||
@@ -78,30 +166,18 @@ void evse_set_consumption_limit(uint32_t value)
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
nvs_handle_t h;
|
||||
esp_err_t err = nvs_open("evse", NVS_READWRITE, &h);
|
||||
if (err == ESP_OK)
|
||||
esp_err_t err = storage_set_u32_async(NVS_NAMESPACE, "def_cons_lim", value);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
err = nvs_set_u32(h, "def_cons_lim", value);
|
||||
if (err == ESP_OK)
|
||||
err = nvs_commit(h);
|
||||
nvs_close(h);
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE("EVSE_LIMITS",
|
||||
"Failed to persist consumption limit (%" PRIu32 " Wh): %s",
|
||||
value, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("EVSE_LIMITS",
|
||||
"Failed to open NVS for consumption limit: %s",
|
||||
esp_err_to_name(err));
|
||||
ESP_LOGE(TAG,
|
||||
"Failed to persist consumption limit (%" PRIu32 " Wh): %s",
|
||||
value, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// Charging time limit
|
||||
// ---------------------------------
|
||||
uint32_t evse_get_charging_time_limit(void)
|
||||
{
|
||||
uint32_t val;
|
||||
@@ -126,30 +202,18 @@ void evse_set_charging_time_limit(uint32_t value)
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
nvs_handle_t h;
|
||||
esp_err_t err = nvs_open("evse", NVS_READWRITE, &h);
|
||||
if (err == ESP_OK)
|
||||
esp_err_t err = storage_set_u32_async(NVS_NAMESPACE, "def_ch_time_lim", value);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
err = nvs_set_u32(h, "def_ch_time_lim", value);
|
||||
if (err == ESP_OK)
|
||||
err = nvs_commit(h);
|
||||
nvs_close(h);
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE("EVSE_LIMITS",
|
||||
"Failed to persist charging time limit (%" PRIu32 " s): %s",
|
||||
value, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("EVSE_LIMITS",
|
||||
"Failed to open NVS for charging time limit: %s",
|
||||
esp_err_to_name(err));
|
||||
ESP_LOGE(TAG,
|
||||
"Failed to persist charging time limit (%" PRIu32 " s): %s",
|
||||
value, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// Under-power limit
|
||||
// ---------------------------------
|
||||
uint16_t evse_get_under_power_limit(void)
|
||||
{
|
||||
uint16_t val;
|
||||
@@ -174,82 +238,64 @@ void evse_set_under_power_limit(uint16_t value)
|
||||
if (!changed)
|
||||
return;
|
||||
|
||||
nvs_handle_t h;
|
||||
esp_err_t err = nvs_open("evse", NVS_READWRITE, &h);
|
||||
if (err == ESP_OK)
|
||||
esp_err_t err = storage_set_u16_async(NVS_NAMESPACE, "def_un_pwr_lim", value);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
err = nvs_set_u16(h, "def_un_pwr_lim", value);
|
||||
if (err == ESP_OK)
|
||||
err = nvs_commit(h);
|
||||
nvs_close(h);
|
||||
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE("EVSE_LIMITS",
|
||||
"Failed to persist under-power limit (%" PRIu32 " W): %s",
|
||||
(uint32_t)value, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE("EVSE_LIMITS",
|
||||
"Failed to open NVS for under-power limit: %s",
|
||||
esp_err_to_name(err));
|
||||
ESP_LOGE(TAG,
|
||||
"Failed to persist under-power limit (%" PRIu32 " W): %s",
|
||||
(uint32_t)value, esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Limit checking logic
|
||||
// ========================
|
||||
|
||||
// ---------------------------------
|
||||
// Runtime check
|
||||
// ---------------------------------
|
||||
void evse_limits_check(void)
|
||||
{
|
||||
// Só faz sentido durante carregamento
|
||||
// Só faz sentido quando há energia ativa (C2/D2)
|
||||
if (!evse_state_is_charging(evse_get_state()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
evse_session_t sess;
|
||||
if (!evse_session_get(&sess) || !sess.is_current)
|
||||
{
|
||||
// Sem sessão ativa → nada a fazer
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t cons_lim;
|
||||
uint32_t time_lim;
|
||||
uint16_t unp_lim;
|
||||
|
||||
portENTER_CRITICAL(&evse_mux);
|
||||
cons_lim = consumption_limit;
|
||||
time_lim = charging_time_limit;
|
||||
unp_lim = under_power_limit;
|
||||
portEXIT_CRITICAL(&evse_mux);
|
||||
|
||||
bool reached = false;
|
||||
|
||||
// 1) Limite de energia (Wh)
|
||||
if (consumption_limit > 0 && sess.energy_wh >= consumption_limit)
|
||||
if (cons_lim > 0 && sess.energy_wh >= cons_lim)
|
||||
{
|
||||
ESP_LOGW("EVSE_LIMITS",
|
||||
"Energy limit reached: %" PRIu32 " Wh ≥ %" PRIu32 " Wh",
|
||||
sess.energy_wh, consumption_limit);
|
||||
ESP_LOGW(TAG, "Energy limit reached: %" PRIu32 " Wh ≥ %" PRIu32 " Wh",
|
||||
sess.energy_wh, cons_lim);
|
||||
reached = true;
|
||||
}
|
||||
|
||||
// 2) Limite de tempo (s)
|
||||
if (charging_time_limit > 0 && sess.duration_s >= charging_time_limit)
|
||||
if (time_lim > 0 && sess.duration_s >= time_lim)
|
||||
{
|
||||
ESP_LOGW("EVSE_LIMITS",
|
||||
"Charging time limit reached: %" PRIu32 " s ≥ %" PRIu32 " s",
|
||||
sess.duration_s, charging_time_limit);
|
||||
ESP_LOGW(TAG, "Charging time limit reached: %" PRIu32 " s ≥ %" PRIu32 " s",
|
||||
sess.duration_s, time_lim);
|
||||
reached = true;
|
||||
}
|
||||
|
||||
// 3) Under-power (potência instantânea)
|
||||
uint32_t inst_power = evse_meter_get_instant_power();
|
||||
if (under_power_limit > 0 && inst_power < under_power_limit)
|
||||
int32_t p = evse_meter_get_instant_power();
|
||||
uint32_t inst_power = (p > 0) ? (uint32_t)p : 0;
|
||||
|
||||
if (unp_lim > 0 && inst_power < (uint32_t)unp_lim)
|
||||
{
|
||||
ESP_LOGW("EVSE_LIMITS",
|
||||
"Under-power limit reached: %" PRIu32 " W < %" PRIu32 " W",
|
||||
(uint32_t)inst_power,
|
||||
(uint32_t)under_power_limit);
|
||||
ESP_LOGW(TAG, "Under-power limit reached: %" PRIu32 " W < %" PRIu32 " W",
|
||||
inst_power, (uint32_t)unp_lim);
|
||||
reached = true;
|
||||
}
|
||||
|
||||
if (reached)
|
||||
{
|
||||
evse_set_limit_reached(true);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user