167 lines
4.2 KiB
C
167 lines
4.2 KiB
C
#include <inttypes.h>
|
|
#include "evse_session.h"
|
|
#include "evse_meter.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "esp_log.h"
|
|
#include "evse_events.h"
|
|
#include "esp_event.h"
|
|
#include "evse_limits.h"
|
|
|
|
static const char *TAG = "evse_session";
|
|
|
|
static TickType_t session_start_tick = 0;
|
|
static uint32_t watt_seconds = 0;
|
|
static evse_session_t last_session;
|
|
static bool last_session_valid = false;
|
|
static uint32_t session_counter = 0;
|
|
|
|
static portMUX_TYPE session_mux = portMUX_INITIALIZER_UNLOCKED;
|
|
|
|
void evse_session_init(void)
|
|
{
|
|
portENTER_CRITICAL(&session_mux);
|
|
session_start_tick = 0;
|
|
watt_seconds = 0;
|
|
last_session_valid = false;
|
|
session_counter = 0;
|
|
portEXIT_CRITICAL(&session_mux);
|
|
}
|
|
|
|
void evse_session_start(void)
|
|
{
|
|
TickType_t tick = xTaskGetTickCount();
|
|
|
|
portENTER_CRITICAL(&session_mux);
|
|
session_start_tick = tick;
|
|
watt_seconds = 0;
|
|
session_counter++;
|
|
portEXIT_CRITICAL(&session_mux);
|
|
|
|
evse_set_limit_reached(false);
|
|
|
|
ESP_LOGI(TAG, "Session started at tick %u", (unsigned)tick);
|
|
|
|
evse_session_event_data_t evt = {
|
|
.type = EVSE_SESSION_EVENT_STARTED,
|
|
.session_id = session_counter,
|
|
.duration_s = 0,
|
|
.energy_wh = 0,
|
|
.avg_power_w = 0,
|
|
.is_current = true,
|
|
};
|
|
|
|
esp_event_post(EVSE_EVENTS,
|
|
EVSE_EVENT_SESSION,
|
|
&evt,
|
|
sizeof(evt),
|
|
portMAX_DELAY);
|
|
}
|
|
|
|
void evse_session_end(void)
|
|
{
|
|
TickType_t start_tick;
|
|
uint32_t ws;
|
|
uint32_t id;
|
|
|
|
portENTER_CRITICAL(&session_mux);
|
|
if (session_start_tick == 0) {
|
|
portEXIT_CRITICAL(&session_mux);
|
|
ESP_LOGW(TAG, "evse_session_end called without active session");
|
|
return;
|
|
}
|
|
start_tick = session_start_tick;
|
|
ws = watt_seconds;
|
|
id = session_counter;
|
|
session_start_tick = 0;
|
|
portEXIT_CRITICAL(&session_mux);
|
|
|
|
TickType_t now = xTaskGetTickCount();
|
|
uint32_t duration_s = (now - start_tick) / configTICK_RATE_HZ;
|
|
uint32_t energy_wh = ws / 3600U;
|
|
uint32_t avg_power = duration_s > 0 ? ws / duration_s : 0;
|
|
|
|
portENTER_CRITICAL(&session_mux);
|
|
last_session.start_tick = 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;
|
|
portEXIT_CRITICAL(&session_mux);
|
|
|
|
ESP_LOGI(TAG,
|
|
"Session ended: duration=%" PRIu32 " s, energy=%" PRIu32
|
|
" Wh, avg_power=%" PRIu32 " W",
|
|
duration_s, energy_wh, avg_power);
|
|
|
|
evse_session_event_data_t evt = {
|
|
.type = EVSE_SESSION_EVENT_FINISHED,
|
|
.session_id = id,
|
|
.duration_s = duration_s,
|
|
.energy_wh = energy_wh,
|
|
.avg_power_w = avg_power,
|
|
.is_current = false,
|
|
};
|
|
|
|
esp_event_post(EVSE_EVENTS,
|
|
EVSE_EVENT_SESSION,
|
|
&evt,
|
|
sizeof(evt),
|
|
portMAX_DELAY);
|
|
}
|
|
|
|
void evse_session_tick(void)
|
|
{
|
|
uint32_t power_w = evse_meter_get_instant_power();
|
|
|
|
portENTER_CRITICAL(&session_mux);
|
|
if (session_start_tick != 0) {
|
|
watt_seconds += power_w;
|
|
}
|
|
portEXIT_CRITICAL(&session_mux);
|
|
}
|
|
|
|
bool evse_session_get(evse_session_t *out)
|
|
{
|
|
if (out == NULL)
|
|
return false;
|
|
|
|
TickType_t start;
|
|
uint32_t ws;
|
|
bool has_current;
|
|
evse_session_t last_copy;
|
|
bool last_valid;
|
|
|
|
portENTER_CRITICAL(&session_mux);
|
|
start = session_start_tick;
|
|
ws = watt_seconds;
|
|
has_current = (session_start_tick != 0);
|
|
last_copy = last_session;
|
|
last_valid = last_session_valid;
|
|
portEXIT_CRITICAL(&session_mux);
|
|
|
|
if (has_current)
|
|
{
|
|
TickType_t now = xTaskGetTickCount();
|
|
uint32_t duration_s = (now - start) / configTICK_RATE_HZ;
|
|
uint32_t energy_wh = ws / 3600U;
|
|
uint32_t avg_power = duration_s > 0 ? ws / duration_s : 0;
|
|
|
|
out->start_tick = start;
|
|
out->duration_s = duration_s;
|
|
out->energy_wh = energy_wh;
|
|
out->avg_power_w = avg_power;
|
|
out->is_current = true;
|
|
return true;
|
|
}
|
|
|
|
if (last_valid)
|
|
{
|
|
*out = last_copy;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|