188 lines
5.1 KiB
C
Executable File
188 lines
5.1 KiB
C
Executable File
#include <inttypes.h> // for PRIu32
|
|
#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"
|
|
|
|
|
|
// ========================
|
|
// External state references
|
|
// ========================
|
|
|
|
//extern evse_state_t current_state; // Current EVSE FSM state
|
|
//extern TickType_t session_start_tick; // Timestamp of charging session start
|
|
|
|
// ========================
|
|
// Concurrency protection
|
|
// ========================
|
|
|
|
static portMUX_TYPE evse_mux = portMUX_INITIALIZER_UNLOCKED;
|
|
|
|
// ========================
|
|
// Runtime state (volatile)
|
|
// ========================
|
|
|
|
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
|
|
|
|
// ========================
|
|
// Default (persistent) limits
|
|
// ========================
|
|
|
|
static uint32_t default_consumption_limit = 0;
|
|
static uint32_t default_charging_time_limit = 0;
|
|
static uint16_t default_under_power_limit = 0;
|
|
|
|
// ========================
|
|
// Limit status flag
|
|
// ========================
|
|
|
|
bool evse_get_limit_reached(void) {
|
|
bool val;
|
|
portENTER_CRITICAL(&evse_mux);
|
|
val = limit_reached;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
return val;
|
|
}
|
|
|
|
void evse_set_limit_reached(bool v) {
|
|
portENTER_CRITICAL(&evse_mux);
|
|
limit_reached = v;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
}
|
|
|
|
// ========================
|
|
// Runtime limit accessors
|
|
// ========================
|
|
|
|
uint32_t evse_get_consumption_limit(void) {
|
|
uint32_t val;
|
|
portENTER_CRITICAL(&evse_mux);
|
|
val = consumption_limit;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
return val;
|
|
}
|
|
|
|
void evse_set_consumption_limit(uint32_t value) {
|
|
portENTER_CRITICAL(&evse_mux);
|
|
consumption_limit = value;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
}
|
|
|
|
uint32_t evse_get_charging_time_limit(void) {
|
|
uint32_t val;
|
|
portENTER_CRITICAL(&evse_mux);
|
|
val = charging_time_limit;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
return val;
|
|
}
|
|
|
|
void evse_set_charging_time_limit(uint32_t value) {
|
|
portENTER_CRITICAL(&evse_mux);
|
|
charging_time_limit = value;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
}
|
|
|
|
uint16_t evse_get_under_power_limit(void) {
|
|
uint16_t val;
|
|
portENTER_CRITICAL(&evse_mux);
|
|
val = under_power_limit;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
return val;
|
|
}
|
|
|
|
void evse_set_under_power_limit(uint16_t value) {
|
|
portENTER_CRITICAL(&evse_mux);
|
|
under_power_limit = value;
|
|
portEXIT_CRITICAL(&evse_mux);
|
|
}
|
|
|
|
// ========================
|
|
// Default (persistent) limit accessors
|
|
// These values can be stored/restored via NVS
|
|
// ========================
|
|
|
|
uint32_t evse_get_default_consumption_limit(void) {
|
|
return default_consumption_limit;
|
|
}
|
|
|
|
void evse_set_default_consumption_limit(uint32_t value) {
|
|
default_consumption_limit = value;
|
|
}
|
|
|
|
uint32_t evse_get_default_charging_time_limit(void) {
|
|
return default_charging_time_limit;
|
|
}
|
|
|
|
void evse_set_default_charging_time_limit(uint32_t value) {
|
|
default_charging_time_limit = value;
|
|
}
|
|
|
|
uint16_t evse_get_default_under_power_limit(void) {
|
|
return default_under_power_limit;
|
|
}
|
|
|
|
void evse_set_default_under_power_limit(uint16_t value) {
|
|
default_under_power_limit = value;
|
|
}
|
|
|
|
bool evse_is_limit_reached(void) {
|
|
return evse_get_limit_reached();
|
|
}
|
|
|
|
// ========================
|
|
// Limit checking logic
|
|
// This function must be called periodically while charging.
|
|
// It will flag the session as "limit reached" when thresholds are violated.
|
|
// ========================
|
|
void evse_limits_check(void) {
|
|
// Only check during an active charging session
|
|
if (!evse_state_is_charging(evse_get_state())) {
|
|
return;
|
|
}
|
|
|
|
evse_session_t sess;
|
|
// Retrieve accumulated data for the current session
|
|
if (!evse_session_get(&sess) || !sess.is_current) {
|
|
// If there's no active session, abort
|
|
return;
|
|
}
|
|
|
|
bool reached = false;
|
|
|
|
// 1) Energy consumption limit (Wh)
|
|
if (consumption_limit > 0 && sess.energy_wh >= consumption_limit) {
|
|
ESP_LOGW("EVSE_LIMITS",
|
|
"Energy limit reached: %" PRIu32 " Wh ≥ %" PRIu32 " Wh",
|
|
sess.energy_wh, consumption_limit);
|
|
reached = true;
|
|
}
|
|
|
|
// 2) Charging time limit (seconds)
|
|
if (charging_time_limit > 0 && sess.duration_s >= charging_time_limit) {
|
|
ESP_LOGW("EVSE_LIMITS",
|
|
"Charging time limit reached: %" PRIu32 " s ≥ %" PRIu32 " s",
|
|
sess.duration_s, charging_time_limit);
|
|
reached = true;
|
|
}
|
|
|
|
// 3) Under-power limit (instantaneous power)
|
|
uint32_t inst_power = evse_meter_get_instant_power();
|
|
if (under_power_limit > 0 && inst_power < under_power_limit) {
|
|
ESP_LOGW("EVSE_LIMITS",
|
|
"Under-power limit reached: %" PRIu32 " W < %" PRIu32 " W",
|
|
(uint32_t)inst_power,
|
|
(uint32_t)under_power_limit);
|
|
reached = true;
|
|
}
|
|
|
|
if (reached) {
|
|
evse_set_limit_reached(true);
|
|
}
|
|
} |