Files
cariflex/tools/EVerest-main/modules/EVSE/EvseManager/EvseManager.hpp
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

441 lines
18 KiB
C++

// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef EVSE_MANAGER_HPP
#define EVSE_MANAGER_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//
#include "ld-ev.hpp"
// headers for provided interface implementations
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
#include <generated/interfaces/dc_external_derate/Implementation.hpp>
#include <generated/interfaces/energy/Implementation.hpp>
#include <generated/interfaces/evse_manager/Implementation.hpp>
#include <generated/interfaces/uk_random_delay/Implementation.hpp>
// headers for required interface implementations
#include <generated/interfaces/ISO15118_charger/Interface.hpp>
#include <generated/interfaces/ac_rcd/Interface.hpp>
#include <generated/interfaces/connector_lock/Interface.hpp>
#include <generated/interfaces/evse_board_support/Interface.hpp>
#include <generated/interfaces/isolation_monitor/Interface.hpp>
#include <generated/interfaces/kvs/Interface.hpp>
#include <generated/interfaces/over_voltage_monitor/Interface.hpp>
#include <generated/interfaces/power_supply_DC/Interface.hpp>
#include <generated/interfaces/powermeter/Interface.hpp>
#include <generated/interfaces/slac/Interface.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <ctime>
#include <date/date.h>
#include <date/tz.h>
#include <future>
#include <iostream>
#include <optional>
#include "CarManufacturer.hpp"
#include "Charger.hpp"
#include "ErrorHandling.hpp"
#include "PersistentStore.hpp"
#include "SessionLog.hpp"
#include "VarContainer.hpp"
#include "over_voltage/OverVoltageMonitor.hpp"
#include "scoped_lock_timeout.hpp"
#include "voltage_plausibility/VoltagePlausibilityMonitor.hpp"
#include <everest/util/async/monitor.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
namespace module {
struct Conf {
int connector_id;
std::string connector_type;
std::string evse_id;
std::string evse_id_din;
bool payment_enable_eim;
bool payment_enable_contract;
double ac_nominal_voltage;
bool ev_receipt_required;
bool session_logging;
std::string session_logging_path;
bool session_logging_xml;
bool has_ventilation;
std::string charge_mode;
bool supported_iso_ac_bpt;
bool ac_hlc_enabled;
bool ac_hlc_use_5percent;
bool ac_enforce_hlc;
bool ac_with_soc;
int internal_over_voltage_duration_ms;
bool dbg_hlc_auth_after_tstep;
int dc_isolation_voltage_V;
int cable_check_wait_number_of_imd_measurements;
bool cable_check_enable_imd_self_test;
bool cable_check_enable_imd_self_test_relays_open;
int cable_check_relays_open_voltage_V;
int cable_check_relays_closed_timeout_s;
bool cable_check_wait_below_60V_before_finish;
bool hack_skoda_enyaq;
int hack_present_current_offset;
bool hack_pause_imd_during_precharge;
bool hack_allow_bpt_with_iso2;
bool hack_simplified_mode_limit_10A;
bool autocharge_use_slac_instead_of_hlc;
bool enable_autocharge;
std::string logfile_suffix;
double soft_over_current_tolerance_percent;
double soft_over_current_measurement_noise_A;
bool hack_fix_hlc_integer_current_requests;
bool disable_authentication;
bool sae_j2847_2_bpt_enabled;
std::string sae_j2847_2_bpt_mode;
bool request_zero_power_in_idle;
bool external_ready_to_start_charging;
bool uk_smartcharging_random_delay_enable;
int uk_smartcharging_random_delay_max_duration;
bool uk_smartcharging_random_delay_at_any_change;
int initial_meter_value_timeout_ms;
int switch_3ph1ph_delay_s;
std::string switch_3ph1ph_cp_state;
int soft_over_current_timeout_ms;
bool lock_connector_in_state_b;
int state_F_after_fault_ms;
bool fail_on_powermeter_errors;
bool raise_mrec9;
int sleep_before_enabling_pwm_hlc_mode_ms;
bool central_contract_validation_allowed;
bool contract_certificate_installation_enabled;
bool inoperative_error_use_vendor_id;
double voltage_plausibility_max_spread_threshold_V;
int voltage_plausibility_fault_duration_ms;
std::string session_id_type;
bool zero_power_ignore_pause;
bool zero_power_allow_ev_to_ignore_pause;
std::string bpt_channel;
std::string bpt_generator_mode;
std::string bpt_grid_code_island_method;
int hlc_charge_loop_without_energy_timeout_s;
int dc_ramp_ampere_per_second;
};
class EvseManager : public Everest::ModuleBase {
public:
EvseManager() = delete;
EvseManager(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider, Everest::TelemetryProvider& telemetry,
std::unique_ptr<evse_managerImplBase> p_evse, std::unique_ptr<energyImplBase> p_energy_grid,
std::unique_ptr<auth_token_providerImplBase> p_token_provider,
std::unique_ptr<uk_random_delayImplBase> p_random_delay,
std::unique_ptr<dc_external_derateImplBase> p_dc_external_derate,
std::unique_ptr<evse_board_supportIntf> r_bsp, std::vector<std::unique_ptr<ac_rcdIntf>> r_ac_rcd,
std::vector<std::unique_ptr<connector_lockIntf>> r_connector_lock,
std::vector<std::unique_ptr<powermeterIntf>> r_powermeter_grid_side,
std::vector<std::unique_ptr<powermeterIntf>> r_powermeter_car_side,
std::vector<std::unique_ptr<slacIntf>> r_slac, std::vector<std::unique_ptr<ISO15118_chargerIntf>> r_hlc,
std::vector<std::unique_ptr<isolation_monitorIntf>> r_imd,
std::vector<std::unique_ptr<over_voltage_monitorIntf>> r_over_voltage_monitor,
std::vector<std::unique_ptr<power_supply_DCIntf>> r_powersupply_DC,
std::vector<std::unique_ptr<kvsIntf>> r_store, Conf& config) :
ModuleBase(info),
mqtt(mqtt_provider),
telemetry(telemetry),
p_evse(std::move(p_evse)),
p_energy_grid(std::move(p_energy_grid)),
p_token_provider(std::move(p_token_provider)),
p_random_delay(std::move(p_random_delay)),
p_dc_external_derate(std::move(p_dc_external_derate)),
r_bsp(std::move(r_bsp)),
r_ac_rcd(std::move(r_ac_rcd)),
r_connector_lock(std::move(r_connector_lock)),
r_powermeter_grid_side(std::move(r_powermeter_grid_side)),
r_powermeter_car_side(std::move(r_powermeter_car_side)),
r_slac(std::move(r_slac)),
r_hlc(std::move(r_hlc)),
r_imd(std::move(r_imd)),
r_over_voltage_monitor(std::move(r_over_voltage_monitor)),
r_powersupply_DC(std::move(r_powersupply_DC)),
r_store(std::move(r_store)),
config(config){};
Everest::MqttProvider& mqtt;
Everest::TelemetryProvider& telemetry;
const std::unique_ptr<evse_managerImplBase> p_evse;
const std::unique_ptr<energyImplBase> p_energy_grid;
const std::unique_ptr<auth_token_providerImplBase> p_token_provider;
const std::unique_ptr<uk_random_delayImplBase> p_random_delay;
const std::unique_ptr<dc_external_derateImplBase> p_dc_external_derate;
const std::unique_ptr<evse_board_supportIntf> r_bsp;
const std::vector<std::unique_ptr<ac_rcdIntf>> r_ac_rcd;
const std::vector<std::unique_ptr<connector_lockIntf>> r_connector_lock;
const std::vector<std::unique_ptr<powermeterIntf>> r_powermeter_grid_side;
const std::vector<std::unique_ptr<powermeterIntf>> r_powermeter_car_side;
const std::vector<std::unique_ptr<slacIntf>> r_slac;
const std::vector<std::unique_ptr<ISO15118_chargerIntf>> r_hlc;
const std::vector<std::unique_ptr<isolation_monitorIntf>> r_imd;
const std::vector<std::unique_ptr<over_voltage_monitorIntf>> r_over_voltage_monitor;
const std::vector<std::unique_ptr<power_supply_DCIntf>> r_powersupply_DC;
const std::vector<std::unique_ptr<kvsIntf>> r_store;
const Conf& config;
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
std::unique_ptr<Charger> charger;
sigslot::signal<int> signalNrOfPhasesAvailable;
types::powermeter::Powermeter get_latest_powermeter_data_billing();
types::evse_board_support::HardwareCapabilities get_hw_capabilities();
std::atomic<bool> ready_for_capabilities{false};
std::mutex external_local_limits_mutex;
bool update_max_current_limit(types::energy::ExternalLimits& limits, float max_current_import,
float max_current_export);
bool update_max_watt_limit(types::energy::ExternalLimits& limits, float max_watt_export,
std::optional<float> max_watt_import);
void update_to_zero_discharge_limit(types::energy::ExternalLimits& limits);
bool update_local_energy_limit(types::energy::ExternalLimits l);
types::energy::ExternalLimits get_local_energy_limits();
void cancel_reservation(bool signal_event);
bool is_reserved();
std::optional<types::evse_manager::ConnectorTypeEnum> connector_type;
///
/// \brief Reserve this evse.
/// \param id The reservation id.
/// \param signal_reservation_event True when other modules must be signalled about a new reservation (session
/// event).
/// \return True on success.
///
bool reserve(int32_t id, const bool signal_reservation_event = true);
int32_t get_reservation_id();
bool get_hlc_waiting_for_auth_pnc();
void set_pnc_enabled(const bool pnc_enabled);
void set_central_contract_validation_allowed(const bool central_contract_validation_allowed);
void set_contract_certificate_installation_enabled(const bool contract_certificate_installation_enabled);
sigslot::signal<types::evse_manager::SessionEvent> signalReservationEvent;
void charger_was_authorized();
const std::vector<std::unique_ptr<powermeterIntf>>& r_powermeter_billing();
// FIXME: this will be removed with proper integration of BPT on ISO-20
// on DIN SPEC and -2 we claim a positive charging current on ISO protocol,
// but the power supply switches to discharge if this flag is set.
std::atomic_bool is_actually_exporting_to_grid{false};
types::evse_manager::EVInfo get_ev_info();
void apply_new_target_voltage_current();
void process_dc_ev_target_voltage_current(const types::iso15118::DcEvseMaximumLimits& hlc_limits);
std::string selected_protocol = "Unknown";
std::atomic_bool sae_bidi_active{false};
void ready_to_start_charging();
std::unique_ptr<IECStateMachine> bsp;
std::unique_ptr<ErrorHandling> error_handling;
std::unique_ptr<PersistentStore> store;
std::atomic_bool random_delay_enabled{false};
std::atomic_bool random_delay_running{false};
std::chrono::time_point<std::chrono::steady_clock> random_delay_end_time;
std::chrono::time_point<date::utc_clock> random_delay_start_time;
std::atomic<std::chrono::seconds> random_delay_max_duration;
std::atomic<std::chrono::time_point<std::chrono::steady_clock>> timepoint_ready_for_charging;
bool session_is_iso_d20_ac_bpt();
bool session_is_iso_d20_dc_bpt();
types::power_supply_DC::Capabilities get_powersupply_capabilities();
void set_external_derating(types::dc_external_derate::ExternalDerating d);
void update_powersupply_capabilities(types::power_supply_DC::Capabilities caps) {
std::scoped_lock lock(powersupply_capabilities_mutex);
if (caps != powersupply_capabilities) {
r_hlc[0]->call_set_powersupply_capabilities(caps);
}
powersupply_capabilities = caps;
// Inform HLC layer about update of physical values
types::iso15118::SetupPhysicalValues setup_physical_values;
setup_physical_values.dc_current_regulation_tolerance = powersupply_capabilities.current_regulation_tolerance_A;
setup_physical_values.dc_peak_current_ripple = powersupply_capabilities.peak_current_ripple_A;
setup_physical_values.dc_energy_to_be_delivered = 10000;
r_hlc[0]->call_set_charging_parameters(setup_physical_values);
types::iso15118::DcEvseMinimumLimits evse_min_limits;
evse_min_limits.evse_minimum_current_limit = powersupply_capabilities.min_export_current_A;
evse_min_limits.evse_minimum_voltage_limit = powersupply_capabilities.min_export_voltage_V;
evse_min_limits.evse_minimum_power_limit =
evse_min_limits.evse_minimum_current_limit * evse_min_limits.evse_minimum_voltage_limit;
r_hlc[0]->call_update_dc_minimum_limits(evse_min_limits);
// HLC layer will also get new maximum current/voltage/watt limits etc, but those will need to run through
// energy management first. Those limits will be applied in energy_grid implementation when requesting
// energy, so it is enough to set the powersupply_capabilities here.
// FIXME: this is not implemented yet: enforce_limits uses the enforced limits to tell HLC, but capabilities
// limits are not yet included in request.
}
std::atomic_int ac_nr_phases_active{0};
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
protected:
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
// insert your protected definitions here
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
private:
friend class LdEverest;
void init();
void ready();
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
// insert your private definitions here
std::mutex powersupply_capabilities_mutex;
types::power_supply_DC::Capabilities powersupply_capabilities;
std::mutex dc_external_derate_mutex;
types::dc_external_derate::ExternalDerating dc_external_derate;
Everest::timed_mutex_traceable power_mutex;
types::powermeter::Powermeter latest_powermeter_data_billing;
Everest::Thread energyThreadHandle;
everest::lib::util::monitor<types::evse_board_support::HardwareCapabilities> hw_capabilities;
types::energy::ExternalLimits external_local_energy_limits;
const float EVSE_ABSOLUTE_MAX_CURRENT = 80.0;
bool slac_enabled;
std::atomic_bool contactor_open{true};
Everest::timed_mutex_traceable charger_ready_mutex;
bool charger_ready{false};
std::atomic_bool hlc_enabled;
std::atomic_bool hlc_waiting_for_auth_eim;
std::atomic_bool hlc_waiting_for_auth_pnc;
std::atomic_bool pnc_enabled{false};
std::atomic_bool central_contract_validation_allowed{false};
std::atomic_bool contract_certificate_installation_enabled{false};
VarContainer<types::isolation_monitor::IsolationMeasurement> isolation_measurement;
VarContainer<types::power_supply_DC::VoltageCurrent> powersupply_measurement;
VarContainer<bool> selftest_result;
std::unique_ptr<OverVoltageMonitor> internal_over_voltage_monitor;
// Track voltage to earth failures for debouncing
int voltage_to_earth_failure_count{0};
std::chrono::steady_clock::time_point first_voltage_to_earth_failure_time{};
static constexpr std::chrono::seconds MIN_TIME_BETWEEN_FIRST_AND_LAST_FAILURE{2};
static constexpr int REQUIRED_CONSECUTIVE_FAILURES{2};
std::atomic<double> latest_target_current_low_pass{0.};
std::atomic<std::chrono::steady_clock::time_point> latest_target_current_low_pass_last_update{};
std::atomic<double> latest_target_voltage{0.};
std::atomic<double> latest_target_current{0.};
std::atomic<double> last_power_supply_voltage{0.};
std::atomic<double> last_power_supply_current{0.};
// Raw EV target values as received from ISO15118 stack
std::atomic<double> raw_ev_target_voltage{0.};
std::atomic<double> raw_ev_target_current{0.};
types::authorization::ProvidedIdToken autocharge_token;
void log_v2g_message(types::iso15118::V2gMessages const& v2g_messages);
// Reservations
bool reserved;
int32_t reservation_id;
Everest::timed_mutex_traceable reservation_mutex;
// Voltage plausibility monitor
std::unique_ptr<VoltagePlausibilityMonitor> voltage_plausibility_monitor;
void setup_AC_mode();
void setup_fake_DC_mode();
// special funtion to switch mode while session is active
void switch_AC_mode();
void switch_DC_mode();
// DC handlers
void cable_check();
void powersupply_DC_on();
std::atomic_bool powersupply_dc_is_on{false};
bool powersupply_DC_set(double voltage, double current);
void powersupply_DC_off();
bool wait_powersupply_DC_voltage_reached(double target_voltage);
bool wait_powersupply_DC_below_voltage(double target_voltage);
bool cable_check_should_exit();
double get_emergency_over_voltage_threshold();
double get_error_over_voltage_threshold();
// EV information
Everest::timed_mutex_traceable ev_info_mutex;
types::evse_manager::EVInfo ev_info;
types::evse_manager::CarManufacturer car_manufacturer{types::evse_manager::CarManufacturer::Unknown};
void imd_stop();
void imd_start();
Everest::Thread telemetryThreadHandle;
void fail_cable_check(const std::string& reason);
// setup sae j2847/2 v2h mode
void setup_v2h_mode();
bool check_isolation_resistance_in_range(double resistance);
bool check_voltage_to_protective_earth_in_range(types::isolation_monitor::IsolationMeasurement m);
static constexpr double CABLECHECK_CURRENT_LIMIT{2};
static constexpr double CABLECHECK_INSULATION_FAULT_RESISTANCE_OHM{100000.};
static constexpr double CABLECHECK_SAFE_VOLTAGE{60.};
static constexpr int CABLECHECK_SELFTEST_TIMEOUT{30};
std::atomic_bool current_demand_active{false};
std::atomic_bool slac_unmatched{false};
std::mutex powermeter_mutex;
std::condition_variable powermeter_cv;
bool initial_powermeter_value_received{false};
std::optional<types::iso15118::ServiceCategory> selected_d20_energy_service{std::nullopt};
std::atomic<types::power_supply_DC::ChargingPhase> power_supply_DC_charging_phase{
types::power_supply_DC::ChargingPhase::Other};
types::power_supply_DC::ChargingPhase last_power_supply_DC_charging_phase{
types::power_supply_DC::ChargingPhase::Other};
everest::lib::util::monitor<std::vector<types::iso15118::EnergyTransferMode>> supported_energy_transfers;
void publish_and_update_supported_energy_transfers();
bool update_supported_energy_transfers(const std::vector<types::iso15118::EnergyTransferMode>& energy_transfers);
bool update_supported_energy_transfers(const types::iso15118::EnergyTransferMode& energy_transfer);
std::mutex hlc_ac_parameters_mutex;
void update_hlc_ac_parameters();
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
};
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
} // namespace module
#endif // EVSE_MANAGER_HPP