new buzzer component
This commit is contained in:
@@ -10,6 +10,8 @@ set(srcs
|
||||
evse_hardware.c
|
||||
evse_pilot.c
|
||||
evse_meter.c
|
||||
evse_session.c
|
||||
evse_api.c
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
|
||||
37
components/evse/evse_api.c
Executable file
37
components/evse/evse_api.c
Executable file
@@ -0,0 +1,37 @@
|
||||
// evse_api.c - Main EVSE control logic
|
||||
|
||||
#include "evse_fsm.h"
|
||||
#include "evse_error.h"
|
||||
#include "evse_limits.h"
|
||||
#include "evse_config.h"
|
||||
#include "evse_api.h"
|
||||
#include "evse_session.h"
|
||||
#include "evse_pilot.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "evse_api";
|
||||
|
||||
|
||||
// ================================
|
||||
// Public Configuration Interface
|
||||
// ================================
|
||||
|
||||
void evse_set_enabled(bool value) {
|
||||
ESP_LOGI(TAG, "Set enabled %d", value);
|
||||
evse_config_set_enabled(value);
|
||||
}
|
||||
|
||||
bool evse_is_available(void) {
|
||||
return evse_config_is_available();
|
||||
}
|
||||
|
||||
void evse_set_available(bool value) {
|
||||
ESP_LOGI(TAG, "Set available %d", value);
|
||||
evse_config_set_available(value);
|
||||
}
|
||||
|
||||
bool evse_get_session(evse_session_t *out) {
|
||||
return evse_session_get(out);
|
||||
}
|
||||
@@ -50,8 +50,8 @@ void evse_check_defaults(void) {
|
||||
|
||||
// Charging current (default, persisted)
|
||||
err = nvs_get_u16(nvs, "def_chrg_curr", &u16);
|
||||
if (err != ESP_OK || u16 < (MIN_CHARGING_CURRENT_LIMIT * 10) || u16 > (max_charging_current * 10)) {
|
||||
charging_current = max_charging_current * 10;
|
||||
if (err != ESP_OK || u16 < (MIN_CHARGING_CURRENT_LIMIT) || u16 > (max_charging_current)) {
|
||||
charging_current = max_charging_current;
|
||||
nvs_set_u16(nvs, "def_chrg_curr", charging_current);
|
||||
needs_commit = true;
|
||||
ESP_LOGW(TAG, "Invalid or missing def_chrg_curr, resetting to %d", charging_current);
|
||||
@@ -136,7 +136,7 @@ uint16_t evse_get_charging_current(void) {
|
||||
}
|
||||
|
||||
esp_err_t evse_set_charging_current(uint16_t value) {
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT * 10) || value > (max_charging_current * 10))
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT) || value > (max_charging_current))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
charging_current = value;
|
||||
nvs_set_u16(nvs, "def_chrg_curr", value);
|
||||
@@ -151,7 +151,7 @@ uint16_t evse_get_default_charging_current(void) {
|
||||
}
|
||||
|
||||
esp_err_t evse_set_default_charging_current(uint16_t value) {
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT * 10) || value > (max_charging_current * 10))
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT) || value > (max_charging_current))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
nvs_set_u16(nvs, "def_chrg_curr", value);
|
||||
return nvs_commit(nvs);
|
||||
@@ -161,12 +161,17 @@ esp_err_t evse_set_default_charging_current(uint16_t value) {
|
||||
// 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;
|
||||
|
||||
if (value > (max_charging_current)) {
|
||||
value= max_charging_current;
|
||||
}
|
||||
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT) ) {
|
||||
value= MIN_CHARGING_CURRENT_LIMIT;
|
||||
}
|
||||
|
||||
charging_current_runtime = value;
|
||||
ESP_LOGD(TAG, "Runtime charging current updated: %d", charging_current_runtime);
|
||||
ESP_LOGI(TAG, "Runtime charging current updated: %d", charging_current_runtime);
|
||||
}
|
||||
|
||||
uint16_t evse_get_runtime_charging_current(void) {
|
||||
@@ -219,18 +224,6 @@ esp_err_t evse_set_temp_threshold(uint8_t value) {
|
||||
return nvs_commit(nvs);
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Authentication
|
||||
// ========================
|
||||
bool evse_is_require_auth(void) {
|
||||
return require_auth;
|
||||
}
|
||||
|
||||
void evse_set_require_auth(bool value) {
|
||||
require_auth = value;
|
||||
nvs_set_u8(nvs, "require_auth", value);
|
||||
nvs_commit(nvs);
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Availability
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "evse_limits.h"
|
||||
#include "evse_config.h"
|
||||
#include "evse_api.h"
|
||||
#include "evse_session.h"
|
||||
#include "evse_pilot.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
@@ -71,25 +72,6 @@ void evse_process(void) {
|
||||
xSemaphoreGive(mutex);
|
||||
}
|
||||
|
||||
|
||||
// ================================
|
||||
// Public Configuration Interface
|
||||
// ================================
|
||||
|
||||
void evse_set_enabled(bool value) {
|
||||
ESP_LOGI(TAG, "Set enabled %d", value);
|
||||
evse_config_set_enabled(value);
|
||||
}
|
||||
|
||||
bool evse_is_available(void) {
|
||||
return evse_config_is_available();
|
||||
}
|
||||
|
||||
void evse_set_available(bool value) {
|
||||
ESP_LOGI(TAG, "Set available %d", value);
|
||||
evse_config_set_available(value);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// Background Task
|
||||
// ================================
|
||||
|
||||
@@ -69,15 +69,16 @@ static void update_outputs(evse_state_t state) {
|
||||
if (board_config.socket_lock && socket_outlet) {
|
||||
socket_lock_set_locked(true);
|
||||
}
|
||||
|
||||
if (rcm_test()) {
|
||||
ESP_LOGI(TAG, "RCM self test passed");
|
||||
//ESP_LOGI(TAG, "RCM self test passed");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "RCM self test failed");
|
||||
//ESP_LOGW(TAG, "RCM self test failed");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVSE_STATE_B2:
|
||||
pilot_set_amps(MIN(current * 10, cable_max_current * 10));
|
||||
pilot_set_amps(MIN(current, cable_max_current));
|
||||
ac_relay_set_state(false);
|
||||
break;
|
||||
|
||||
@@ -90,7 +91,7 @@ static void update_outputs(evse_state_t state) {
|
||||
|
||||
case EVSE_STATE_C2:
|
||||
case EVSE_STATE_D2:
|
||||
pilot_set_amps(MIN(current * 10, cable_max_current * 10));
|
||||
pilot_set_amps(MIN(current, cable_max_current));
|
||||
ac_relay_set_state(true); // Só chega aqui se não há erro!
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#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"
|
||||
@@ -134,41 +136,53 @@ 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) {
|
||||
evse_state_t state = evse_get_state();
|
||||
if (!evse_state_is_charging(state)) return;
|
||||
// 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;
|
||||
|
||||
uint32_t energy = evse_meter_get_total_energy();
|
||||
uint32_t power = evse_meter_get_instant_power();
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
TickType_t start = evse_get_session_start();
|
||||
|
||||
if (consumption_limit > 0 && energy >= consumption_limit) {
|
||||
ESP_LOGW("EVSE", "Energy limit reached");
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (charging_time_limit > 0 &&
|
||||
(now - start) >= pdMS_TO_TICKS(charging_time_limit * 1000)) {
|
||||
ESP_LOGW("EVSE", "Charging time limit reached");
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (under_power_limit > 0 && power < under_power_limit) {
|
||||
ESP_LOGW("EVSE", "Under power limit reached");
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "evse_config.h"
|
||||
#include "evse_api.h"
|
||||
#include "evse_meter.h"
|
||||
#include "evse_session.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -89,6 +90,7 @@ void evse_manager_init(void) {
|
||||
evse_hardware_init();
|
||||
evse_state_init();
|
||||
evse_meter_init();
|
||||
evse_session_init();
|
||||
|
||||
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));
|
||||
@@ -105,6 +107,7 @@ void evse_manager_tick(void) {
|
||||
evse_error_tick();
|
||||
evse_state_tick();
|
||||
evse_temperature_check();
|
||||
evse_session_tick();
|
||||
|
||||
if (auth_enabled) {
|
||||
// If the car is disconnected, revoke authorization
|
||||
|
||||
@@ -41,7 +41,7 @@ void evse_meter_on_meter_event(void* arg, void* event_data) {
|
||||
meter_data.energy_wh = (uint32_t)(evt->total_energy * 1000.0f);
|
||||
xSemaphoreGive(meter_mutex);
|
||||
|
||||
ESP_LOGD(TAG,
|
||||
ESP_LOGI(TAG,
|
||||
"Meter updated: power[W]={%" PRIu32 ",%" PRIu32 ",%" PRIu32 "}, "
|
||||
"voltage[V]={%.2f,%.2f,%.2f}, "
|
||||
"current[A]={%.2f,%.2f,%.2f}, "
|
||||
@@ -63,9 +63,9 @@ void evse_meter_init(void) {
|
||||
ESP_LOGI(TAG, "EVSE Meter listener registered.");
|
||||
}
|
||||
|
||||
uint32_t evse_meter_get_instant_power(void) {
|
||||
int evse_meter_get_instant_power(void) {
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
uint32_t sum = 0;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
sum += meter_data.power_watts[i];
|
||||
}
|
||||
@@ -73,14 +73,14 @@ uint32_t evse_meter_get_instant_power(void) {
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint32_t evse_meter_get_total_energy(void) {
|
||||
int evse_meter_get_total_energy(void) {
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
uint32_t val = meter_data.energy_wh;
|
||||
int val = meter_data.energy_wh;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
return val;
|
||||
}
|
||||
|
||||
void evse_meter_get_power(uint32_t power[EVSE_METER_PHASE_COUNT]) {
|
||||
void evse_meter_get_power(int power[EVSE_METER_PHASE_COUNT]) {
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
power[i] = meter_data.power_watts[i];
|
||||
|
||||
@@ -79,28 +79,36 @@ void pilot_set_level(bool level)
|
||||
|
||||
void pilot_set_amps(uint16_t amps)
|
||||
{
|
||||
if (amps < 60 || amps > 800) {
|
||||
ESP_LOGE(TAG, "Invalid ampere value: %d A*10", amps);
|
||||
if (amps < 6 || amps > 80) {
|
||||
ESP_LOGE(TAG, "Invalid ampere value: %d A (valid: 6–80 A)", amps);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t duty;
|
||||
if (amps <= 510) {
|
||||
duty = (PILOT_PWM_MAX_DUTY * amps) / 600;
|
||||
uint32_t duty_percent;
|
||||
|
||||
if (amps <= 51) {
|
||||
duty_percent = (amps * 10) / 6; // Duty (%) = Amps / 0.6
|
||||
} else {
|
||||
duty = ((PILOT_PWM_MAX_DUTY * amps) / 2500) + (64 * (PILOT_PWM_MAX_DUTY / 100));
|
||||
duty_percent = (amps * 10) / 25 + 64; // Duty (%) = (Amps / 2.5) + 64
|
||||
}
|
||||
if (duty > PILOT_PWM_MAX_DUTY) duty = PILOT_PWM_MAX_DUTY;
|
||||
|
||||
if (duty_percent > 100) duty_percent = 100;
|
||||
|
||||
uint32_t duty = (PILOT_PWM_MAX_DUTY * duty_percent) / 100;
|
||||
|
||||
if (last_pilot_level == 0 && last_pwm_duty == duty) return;
|
||||
last_pilot_level = 0;
|
||||
last_pwm_duty = duty;
|
||||
|
||||
ESP_LOGI(TAG, "Set amp %dA*10 -> duty %lu/%d", amps, duty, PILOT_PWM_MAX_DUTY);
|
||||
ESP_LOGI(TAG, "Pilot set: %d A → %d/%d (≈ %d%% duty)",
|
||||
amps, (int)duty, PILOT_PWM_MAX_DUTY, (int)duty_percent);
|
||||
|
||||
ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty);
|
||||
ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int compare_int(const void *a, const void *b) {
|
||||
return (*(int *)a - *(int *)b);
|
||||
}
|
||||
|
||||
84
components/evse/evse_session.c
Normal file
84
components/evse/evse_session.c
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* evse_session.c
|
||||
* Implementation of evse_session module using instantaneous power accumulation
|
||||
*/
|
||||
#include <inttypes.h> // for PRIu32
|
||||
#include "evse_session.h"
|
||||
#include "evse_meter.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "evse_session";
|
||||
|
||||
// Internal state
|
||||
static TickType_t session_start_tick = 0;
|
||||
static uint32_t watt_seconds = 0; // accumulator of W·s
|
||||
static evse_session_t last_session;
|
||||
static bool last_session_valid = false;
|
||||
|
||||
void evse_session_init(void) {
|
||||
session_start_tick = 0;
|
||||
watt_seconds = 0;
|
||||
last_session_valid = false;
|
||||
}
|
||||
|
||||
void evse_session_start(void) {
|
||||
session_start_tick = xTaskGetTickCount();
|
||||
watt_seconds = 0;
|
||||
ESP_LOGI(TAG, "Session started at tick %u", (unsigned)session_start_tick);
|
||||
}
|
||||
|
||||
void evse_session_end(void) {
|
||||
if (session_start_tick == 0) {
|
||||
ESP_LOGW(TAG, "evse_session_end called without active session");
|
||||
return;
|
||||
}
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
uint32_t duration_s = (now - session_start_tick) / configTICK_RATE_HZ;
|
||||
uint32_t energy_wh = watt_seconds / 3600U;
|
||||
uint32_t avg_power = duration_s > 0 ? watt_seconds / duration_s : 0;
|
||||
|
||||
last_session.start_tick = session_start_tick;
|
||||
last_session.duration_s = duration_s;
|
||||
last_session.energy_wh = energy_wh;
|
||||
last_session.avg_power_w = avg_power;
|
||||
last_session.is_current = false;
|
||||
last_session_valid = true;
|
||||
|
||||
session_start_tick = 0;
|
||||
ESP_LOGI(TAG, "Session ended: duration=%" PRIu32 " s, energy=%" PRIu32 " Wh, avg_power=%" PRIu32 " W",
|
||||
(uint32_t)duration_s, (uint32_t)energy_wh, (uint32_t)avg_power);
|
||||
}
|
||||
|
||||
void evse_session_tick(void) {
|
||||
if (session_start_tick == 0) return;
|
||||
// Should be called every second (or known interval)
|
||||
uint32_t power_w = evse_meter_get_instant_power();
|
||||
watt_seconds += power_w;
|
||||
}
|
||||
|
||||
bool evse_session_get(evse_session_t *out) {
|
||||
if (out == NULL) return false;
|
||||
|
||||
if (session_start_tick != 0) {
|
||||
TickType_t now = xTaskGetTickCount();
|
||||
uint32_t duration_s = (now - session_start_tick) / configTICK_RATE_HZ;
|
||||
uint32_t energy_wh = watt_seconds / 3600U;
|
||||
uint32_t avg_power = duration_s > 0 ? watt_seconds / duration_s : 0;
|
||||
|
||||
out->start_tick = session_start_tick;
|
||||
out->duration_s = duration_s;
|
||||
out->energy_wh = energy_wh;
|
||||
out->avg_power_w = avg_power;
|
||||
out->is_current = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (last_session_valid) {
|
||||
*out = last_session;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "evse_api.h"
|
||||
#include "evse_state.h"
|
||||
#include "evse_session.h"
|
||||
#include "evse_events.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
@@ -11,10 +12,11 @@
|
||||
|
||||
static evse_state_t current_state = EVSE_STATE_A;
|
||||
static bool is_authorized = false;
|
||||
static TickType_t session_start_tick = 0;
|
||||
|
||||
static portMUX_TYPE state_mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static const char *TAG = "evse_state";
|
||||
|
||||
// =========================
|
||||
// Internal Mapping
|
||||
// =========================
|
||||
@@ -36,34 +38,45 @@ static evse_state_event_t map_state_to_event(evse_state_t s) {
|
||||
// Public API
|
||||
// =========================
|
||||
|
||||
void evse_set_state(evse_state_t state) {
|
||||
void evse_set_state(evse_state_t new_state) {
|
||||
bool changed = false;
|
||||
evse_state_t previous_state;
|
||||
evse_state_t prev_state;
|
||||
bool start_session = false;
|
||||
bool end_session = false;
|
||||
|
||||
// 1) Detecta transição de estado dentro da região crítica
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
previous_state = current_state;
|
||||
if (state != current_state) {
|
||||
current_state = state;
|
||||
changed = true;
|
||||
|
||||
// When entering a charging state, record the start tick
|
||||
if (evse_state_is_charging(state) && !evse_state_is_charging(previous_state)) {
|
||||
session_start_tick = xTaskGetTickCount();
|
||||
}
|
||||
// When exiting a charging state, reset the start tick
|
||||
else if (!evse_state_is_charging(state) && evse_state_is_charging(previous_state)) {
|
||||
session_start_tick = 0;
|
||||
}
|
||||
}
|
||||
prev_state = current_state;
|
||||
if (new_state != current_state) {
|
||||
// se entrou em charging pela primeira vez
|
||||
if (evse_state_is_charging(new_state) && !evse_state_is_charging(prev_state)) {
|
||||
start_session = true;
|
||||
}
|
||||
// se saiu de charging para qualquer outro
|
||||
else if (!evse_state_is_charging(new_state) && evse_state_is_charging(prev_state)) {
|
||||
end_session = true;
|
||||
}
|
||||
current_state = new_state;
|
||||
changed = true;
|
||||
}
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
|
||||
// 2) Executa start/end de sessão FORA da região crítica, evitando logs/alloc dentro dela
|
||||
if (start_session) {
|
||||
evse_session_start();
|
||||
}
|
||||
if (end_session) {
|
||||
evse_session_end();
|
||||
}
|
||||
|
||||
// 3) Se mudou o estado, faz log e dispara evento
|
||||
if (changed) {
|
||||
ESP_LOGI("EVSE_STATE", "State changed from %s to %s",
|
||||
evse_state_to_str(previous_state),
|
||||
evse_state_to_str(state));
|
||||
const char *prev_str = evse_state_to_str(prev_state);
|
||||
const char *curr_str = evse_state_to_str(new_state);
|
||||
ESP_LOGI(TAG, "State changed: %s → %s", prev_str, curr_str);
|
||||
|
||||
evse_state_event_data_t evt = {
|
||||
.state = map_state_to_event(state)
|
||||
.state = map_state_to_event(new_state)
|
||||
};
|
||||
esp_event_post(EVSE_EVENTS,
|
||||
EVSE_EVENT_STATE_CHANGED,
|
||||
@@ -73,6 +86,8 @@ void evse_set_state(evse_state_t state) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
evse_state_t evse_get_state(void) {
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
evse_state_t s = current_state;
|
||||
@@ -80,13 +95,6 @@ evse_state_t evse_get_state(void) {
|
||||
return s;
|
||||
}
|
||||
|
||||
TickType_t evse_get_session_start(void) {
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
TickType_t t = session_start_tick;
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
return t;
|
||||
}
|
||||
|
||||
const char* evse_state_to_str(evse_state_t state) {
|
||||
switch (state) {
|
||||
case EVSE_STATE_A: return "A - EV Not Connected (12V)";
|
||||
@@ -105,7 +113,6 @@ const char* evse_state_to_str(evse_state_t state) {
|
||||
void evse_state_init(void) {
|
||||
portENTER_CRITICAL(&state_mux);
|
||||
current_state = EVSE_STATE_A;
|
||||
session_start_tick = xTaskGetTickCount();
|
||||
is_authorized = true;
|
||||
portEXIT_CRITICAL(&state_mux);
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "evse_state.h" // Tipos e estados
|
||||
#include "evse_state.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "evse_session.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -24,10 +26,17 @@ evse_state_t evse_get_state(void);
|
||||
*/
|
||||
void evse_set_state(evse_state_t state);
|
||||
|
||||
// ===============================
|
||||
// Charging Session Info
|
||||
// ===============================
|
||||
|
||||
/**
|
||||
* @brief Get timestamp when the current session started (for timing limits).
|
||||
* @brief Retrieve statistics of either the current ongoing session (if any)
|
||||
* or the last completed session.
|
||||
* @param out pointer to evse_session_t to be filled
|
||||
* @return true if there is a current or last session available
|
||||
*/
|
||||
TickType_t evse_get_session_start(void);
|
||||
bool evse_get_session(evse_session_t *out);
|
||||
|
||||
// ===============================
|
||||
// Charging Session Info
|
||||
|
||||
@@ -55,10 +55,6 @@ esp_err_t evse_set_rcm(bool rcm);
|
||||
uint8_t evse_get_temp_threshold(void);
|
||||
esp_err_t evse_set_temp_threshold(uint8_t threshold);
|
||||
|
||||
// Autenticação
|
||||
bool evse_is_require_auth(void);
|
||||
void evse_set_require_auth(bool require);
|
||||
|
||||
// Disponibilidade
|
||||
bool evse_config_is_available(void);
|
||||
void evse_config_set_available(bool available);
|
||||
|
||||
@@ -13,13 +13,13 @@ extern "C" {
|
||||
void evse_meter_init(void);
|
||||
|
||||
/// Retorna a potência instantânea (soma das 3 fases, em watts)
|
||||
uint32_t evse_meter_get_instant_power(void);
|
||||
int evse_meter_get_instant_power(void);
|
||||
|
||||
/// Retorna a energia total acumulada (em Wh)
|
||||
uint32_t evse_meter_get_total_energy(void);
|
||||
int evse_meter_get_total_energy(void);
|
||||
|
||||
/// Retorna as potências instantâneas nas fases L1, L2 e L3 (em watts)
|
||||
void evse_meter_get_power(uint32_t power[EVSE_METER_PHASE_COUNT]);
|
||||
void evse_meter_get_power(int power[EVSE_METER_PHASE_COUNT]);
|
||||
|
||||
/// Retorna as tensões medidas nas fases L1, L2 e L3 (em volts)
|
||||
void evse_meter_get_voltage(float voltage[EVSE_METER_PHASE_COUNT]);
|
||||
|
||||
53
components/evse/include/evse_session.h
Normal file
53
components/evse/include/evse_session.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* evse_session.h
|
||||
* Module to track and retrieve charging session data (current or last completed),
|
||||
* accumulating energy via periodic tick of instantaneous power.
|
||||
*/
|
||||
|
||||
#ifndef EVSE_SESSION_H
|
||||
#define EVSE_SESSION_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
/**
|
||||
* @brief Charging session statistics
|
||||
*/
|
||||
typedef struct {
|
||||
TickType_t start_tick; ///< tick when session began
|
||||
uint32_t duration_s; ///< total duration in seconds
|
||||
uint32_t energy_wh; ///< total energy consumed in Wh
|
||||
uint32_t avg_power_w; ///< average power in W
|
||||
bool is_current; ///< true if session still in progress
|
||||
} evse_session_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the session module
|
||||
*/
|
||||
void evse_session_init(void);
|
||||
|
||||
/**
|
||||
* @brief Mark the beginning of a charging session
|
||||
*/
|
||||
void evse_session_start(void);
|
||||
|
||||
/**
|
||||
* @brief Mark the end of the charging session and store it as "last session"
|
||||
*/
|
||||
void evse_session_end(void);
|
||||
|
||||
/**
|
||||
* @brief Periodic tick: must be called (e.g., each 1s) to accumulate energy from instant power
|
||||
*/
|
||||
void evse_session_tick(void);
|
||||
|
||||
/**
|
||||
* @brief Retrieve statistics of either the current ongoing session (if any) or
|
||||
* the last completed session.
|
||||
* @param out pointer to evse_session_t to be filled
|
||||
* @return true if there is a current or last session available, false otherwise
|
||||
*/
|
||||
bool evse_session_get(evse_session_t *out);
|
||||
|
||||
#endif // EVSE_SESSION_H
|
||||
@@ -53,11 +53,6 @@ evse_state_t evse_get_state(void);
|
||||
*/
|
||||
void evse_set_state(evse_state_t state);
|
||||
|
||||
/**
|
||||
* @brief Returns the tick count when the current charging session began.
|
||||
*/
|
||||
TickType_t evse_get_session_start(void);
|
||||
|
||||
/**
|
||||
* @brief Converts the state enum into a human-readable string.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user