Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce EVSE Manager configuration option for failing charging if t… #993

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions doc/ocmf/powermeter_start_transaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
```mermaid

Check notice on line 1 in doc/ocmf/powermeter_start_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_start_transaction.md#L1

First line in a file should be a top-level heading
sequenceDiagram
autonumber
participant Powermeter
participant EvseManager
participant OCPP
participant CSMS

title Start of a Transaction

Note over EvseManager: User plugs in EV and authorizes

EvseManager->>OCPP: Event(SessionStarted)

OCPP->>CSMS: StatusNotification.req(Preparing)
CSMS-->>OCPP: StatusNotification.conf

alt successful case
EvseManager->>Powermeter: startTransaction
Powermeter-->>EvseManager: startTransaction Response (OK/ID)

EvseManager->>OCPP: Event(TransactionStarted)
OCPP->>CSMS: StartTransaction.req
CSMS-->>OCPP: StartTransaction.conf

Note over EvseManager: Transaction started successfully

else startTransaction failing due to power loss
EvseManager->>Powermeter: startTransaction
Powermeter-->>EvseManager: startTransaction Response (FAIL)

EvseManager->>OCPP: Event(Deauthorized)

OCPP->>CSMS: StatusNotification.req(Finishing)
CSMS-->>OCPP: StatusNotification.conf

EvseManager->>OCPP: raiseError (PowermeterTransactionStartFailed)
OCPP->>CSMS: StatusNotification.req(Finishing, PowermeterTransactionStartFailed)
CSMS-->>OCPP: StatusNotification.conf

Note over EvseManager: Transaction did not start
end

alt EvseManager configured to become inoperative in case of Powermeter CommunicationError
Powermeter->>EvseManager: raise_error(CommunicationError)
Note over Powermeter,EvseManager: Powermeter raises a CommunicationError <br/>and EvseManager is registered for notification

Check notice on line 46 in doc/ocmf/powermeter_start_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_start_transaction.md#L46

Expected: 80; Actual: 128
EvseManager->>OCPP: raise_error (Inoperative)
OCPP->>CSMS: StatusNotification.req(Faulted)
CSMS-->>OCPP: StatusNotification.conf
end

```

Check notice on line 52 in doc/ocmf/powermeter_start_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_start_transaction.md#L52

Files should end with a single newline character
46 changes: 46 additions & 0 deletions doc/ocmf/powermeter_stop_transaction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
```mermaid

Check notice on line 1 in doc/ocmf/powermeter_stop_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_stop_transaction.md#L1

First line in a file should be a top-level heading
sequenceDiagram
autonumber
participant Powermeter
participant EvseManager
participant OCPP
participant CSMS

title Stopping Transaction in Error

Note over Powermeter, CSMS: Transaction is running

Powermeter->>Powermeter: detects a <br/> CommunicationError
Note over Powermeter,EvseManager: Powermeter raises a CommunicationError <br/>and EvseManager is registered for notification

Check notice on line 14 in doc/ocmf/powermeter_stop_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_stop_transaction.md#L14

Expected: 80; Actual: 124
Powermeter->>EvseManager: raise_error (CommunicationFault)
Powermeter->>OCPP: raise_error (CommunicationFault)

OCPP->>CSMS: StatusNotification.req(Charging, CommunicationFault)
CSMS-->>OCPP: StatusNotification.conf

alt EvseManager configured to become inoperative in case of PowermeterCommError
EvseManager->>EvseManager: Pause charging
EvseManager->>OCPP: raiseError (Inoperative)
OCPP->>CSMS: StatusNotification.req(Faulted)
Note over EvseManager: Note that we would just continue charging otherwise
end

Note over Powermeter, CSMS: User stops the transaction

alt successful case (Powermeter has no CommunicationError)
EvseManager->>Powermeter: stopTransaction (ID)
Powermeter-->>EvseManager: stopTransaction Response (OK/OCMF)
EvseManager->>OCPP: Event(TransactionFinished(OCMF))

OCPP->>CSMS: StopTransaction.req(OCMF)
CSMS-->>OCPP: StopTransaction.conf
else stopTransaction failing due to subsequent power loss (this applies as well when Powermeter still in CommunicationError)

Check notice on line 37 in doc/ocmf/powermeter_stop_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_stop_transaction.md#L37

Expected: 80; Actual: 124
EvseManager->>Powermeter: stopTransaction (ID)
Powermeter->>EvseManager: stopTransaction Response (FAIL)
EvseManager->>OCPP: Event(TransactionFinished)

Note right of OCPP: In this case we can't stop the transaction including the OCMF

Check notice on line 42 in doc/ocmf/powermeter_stop_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_stop_transaction.md#L42

Expected: 80; Actual: 85
OCPP->>CSMS: StopTransaction.req()
CSMS-->>OCPP: StopTransaction.conf
end
```

Check notice on line 46 in doc/ocmf/powermeter_stop_transaction.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/ocmf/powermeter_stop_transaction.md#L46

Files should end with a single newline character
13 changes: 8 additions & 5 deletions modules/EvseManager/Charger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1205,14 +1205,15 @@ bool Charger::start_transaction() {
// we can't bill the customer.
if (response.status == types::powermeter::TransactionRequestStatus::UNEXPECTED_ERROR) {
EVLOG_error << "Failed to start a transaction on the power meter " << response.error.value_or("");
error_handling->raise_powermeter_transaction_start_failed_error(
"Failed to start transaction on the power meter");
return false;
if (true == config_context.fail_on_powermeter_errors) {
error_handling->raise_powermeter_transaction_start_failed_error(
"Failed to start transaction on the power meter");
return false;
}
}
}

store->store_session(shared_context.session_uuid);

signal_transaction_started_event(shared_context.id_token);
return true;
}
Expand Down Expand Up @@ -1324,7 +1325,8 @@ void Charger::setup(bool has_ventilation, const ChargeMode _charge_mode, bool _a
bool _ac_hlc_use_5percent, bool _ac_enforce_hlc, bool _ac_with_soc_timeout,
float _soft_over_current_tolerance_percent, float _soft_over_current_measurement_noise_A,
const int _switch_3ph1ph_delay_s, const std::string _switch_3ph1ph_cp_state,
const int _soft_over_current_timeout_ms, const int _state_F_after_fault_ms) {
const int _soft_over_current_timeout_ms, const int _state_F_after_fault_ms,
const bool fail_on_powermeter_errors) {
// set up board support package
bsp->setup(has_ventilation);

Expand All @@ -1344,6 +1346,7 @@ void Charger::setup(bool has_ventilation, const ChargeMode _charge_mode, bool _a
config_context.switch_3ph1ph_cp_state_F = _switch_3ph1ph_cp_state == "F";

config_context.state_F_after_fault_ms = _state_F_after_fault_ms;
config_context.fail_on_powermeter_errors = fail_on_powermeter_errors;

if (config_context.charge_mode == ChargeMode::AC and config_context.ac_hlc_enabled)
EVLOG_info << "AC HLC mode enabled.";
Expand Down
4 changes: 3 additions & 1 deletion modules/EvseManager/Charger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class Charger {
bool ac_enforce_hlc, bool ac_with_soc_timeout, float soft_over_current_tolerance_percent,
float soft_over_current_measurement_noise_A, const int switch_3ph1ph_delay_s,
const std::string switch_3ph1ph_cp_state, const int soft_over_current_timeout_ms,
const int _state_F_after_fault_ms);
const int _state_F_after_fault_ms, const bool fail_on_powermeter_errors);

bool enable_disable(int connector_id, const types::evse_manager::EnableDisableSource& source);

Expand Down Expand Up @@ -327,6 +327,8 @@ class Charger {
int soft_over_current_timeout_ms{7000};
// Switch to F for configured ms after a fatal error
int state_F_after_fault_ms{300};
// Fail on powermeter errors
bool fail_on_powermeter_errors;
} config_context;

// Used by different threads, but requires no complete state machine locking
Expand Down
23 changes: 20 additions & 3 deletions modules/EvseManager/ErrorHandling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ static const struct IgnoreErrors {
ErrorList ac_rcd{"ac_rcd/VendorWarning"};
ErrorList imd{"isolation_monitor/VendorWarning"};
ErrorList powersupply{"power_supply_DC/VendorWarning"};
ErrorList powermeter{};
} ignore_errors;

ErrorHandling::ErrorHandling(const std::unique_ptr<evse_board_supportIntf>& _r_bsp,
Expand All @@ -23,14 +24,16 @@ ErrorHandling::ErrorHandling(const std::unique_ptr<evse_board_supportIntf>& _r_b
const std::vector<std::unique_ptr<ac_rcdIntf>>& _r_ac_rcd,
const std::unique_ptr<evse_managerImplBase>& _p_evse,
const std::vector<std::unique_ptr<isolation_monitorIntf>>& _r_imd,
const std::vector<std::unique_ptr<power_supply_DCIntf>>& _r_powersupply) :
const std::vector<std::unique_ptr<power_supply_DCIntf>>& _r_powersupply,
const std::vector<std::unique_ptr<powermeterIntf>>& _r_powermeter) :
r_bsp(_r_bsp),
r_hlc(_r_hlc),
r_connector_lock(_r_connector_lock),
r_ac_rcd(_r_ac_rcd),
p_evse(_p_evse),
r_imd(_r_imd),
r_powersupply(_r_powersupply) {
r_powersupply(_r_powersupply),
r_powermeter(_r_powermeter) {

// Subscribe to bsp driver to receive Errors from the bsp hardware
r_bsp->subscribe_all_errors([this](const Everest::error::Error& error) { process_error(); },
Expand Down Expand Up @@ -59,6 +62,12 @@ ErrorHandling::ErrorHandling(const std::unique_ptr<evse_board_supportIntf>& _r_b
r_powersupply[0]->subscribe_all_errors([this](const Everest::error::Error& error) { process_error(); },
[this](const Everest::error::Error& error) { process_error(); });
}

// Subscribe to powermeter to receive errors from powermeter hardware
if (r_powermeter.size() > 0) {
r_powermeter[0]->subscribe_all_errors([this](const Everest::error::Error& error) { process_error(); },
[this](const Everest::error::Error& error) { process_error(); });
}
}

void ErrorHandling::raise_overcurrent_error(const std::string& description) {
Expand Down Expand Up @@ -102,7 +111,8 @@ void ErrorHandling::process_error() {
const int error_count = p_evse->error_state_monitor->get_active_errors().size() +
r_bsp->error_state_monitor->get_active_errors().size() +
number_of_active_errors(r_connector_lock) + number_of_active_errors(r_ac_rcd) +
number_of_active_errors(r_imd) + number_of_active_errors(r_powersupply);
number_of_active_errors(r_imd) + number_of_active_errors(r_powersupply) +
number_of_active_errors(r_powermeter);

if (error_count == 0) {
signal_all_errors_cleared();
Expand Down Expand Up @@ -159,6 +169,13 @@ std::optional<std::string> ErrorHandling::errors_prevent_charging() {
}
}

if (r_powermeter.size() > 0) {
fatal = is_fatal(r_powermeter[0]->error_state_monitor->get_active_errors(), ignore_errors.powermeter);
if (fatal) {
return fatal;
}
}

return std::nullopt;
}

Expand Down
5 changes: 4 additions & 1 deletion modules/EvseManager/ErrorHandling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <generated/interfaces/evse_manager/Interface.hpp>
#include <generated/interfaces/isolation_monitor/Interface.hpp>
#include <generated/interfaces/power_supply_DC/Interface.hpp>
#include <generated/interfaces/powermeter/Interface.hpp>
#include <sigslot/signal.hpp>

#include "Timeout.hpp"
Expand All @@ -47,7 +48,8 @@
const std::vector<std::unique_ptr<ac_rcdIntf>>& r_ac_rcd,
const std::unique_ptr<evse_managerImplBase>& _p_evse,
const std::vector<std::unique_ptr<isolation_monitorIntf>>& _r_imd,
const std::vector<std::unique_ptr<power_supply_DCIntf>>& _r_powersupply);
const std::vector<std::unique_ptr<power_supply_DCIntf>>& _r_powersupply,
const std::vector<std::unique_ptr<powermeterIntf>>& _r_powermeter);

// Signal that error set has changed. Bool argument is true if it is preventing charging at the moment and false if
// charging can continue.
Expand Down Expand Up @@ -77,6 +79,7 @@
const std::unique_ptr<evse_managerImplBase>& p_evse;
const std::vector<std::unique_ptr<isolation_monitorIntf>>& r_imd;
const std::vector<std::unique_ptr<power_supply_DCIntf>>& r_powersupply;
const std::vector<std::unique_ptr<powermeterIntf>>& r_powermeter;

Check notice on line 82 in modules/EvseManager/ErrorHandling.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/EvseManager/ErrorHandling.hpp#L82

class member 'ErrorHandling::r_powermeter' is never used.
};

} // namespace module
Expand Down
15 changes: 11 additions & 4 deletions modules/EvseManager/EvseManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,13 @@ void EvseManager::ready() {
bsp->set_ev_simplified_mode_evse_limit(true);
}

// we provide the powermeter interface to the ErrorHandling only if we need to react to powermeter errors
// otherwise we provide an empty vector of pointers to the powermeter interface
const std::vector<std::unique_ptr<powermeterIntf>> empty;
error_handling = std::unique_ptr<ErrorHandling>(
new ErrorHandling(r_bsp, r_hlc, r_connector_lock, r_ac_rcd, p_evse, r_imd, r_powersupply_DC));
new ErrorHandling(r_bsp, r_hlc, r_connector_lock, r_ac_rcd, p_evse, r_imd, r_powersupply_DC,
config.fail_on_powermeter_errors ? r_powermeter_billing() : empty));

if (not config.lock_connector_in_state_b) {
EVLOG_warning << "Unlock connector in CP state B. This violates IEC61851-1:2019 D.6.5 Table D.9 line 4 and "
"should not be used in public environments!";
Expand Down Expand Up @@ -888,7 +893,7 @@ void EvseManager::ready() {
config.ac_hlc_use_5percent, config.ac_enforce_hlc, false,
config.soft_over_current_tolerance_percent, config.soft_over_current_measurement_noise_A,
config.switch_3ph1ph_delay_s, config.switch_3ph1ph_cp_state, config.soft_over_current_timeout_ms,
config.state_F_after_fault_ms);
config.state_F_after_fault_ms, config.fail_on_powermeter_errors);
}

telemetryThreadHandle = std::thread([this]() {
Expand Down Expand Up @@ -1074,7 +1079,8 @@ void EvseManager::setup_fake_DC_mode() {
charger->setup(config.has_ventilation, Charger::ChargeMode::DC, hlc_enabled, config.ac_hlc_use_5percent,
config.ac_enforce_hlc, false, config.soft_over_current_tolerance_percent,
config.soft_over_current_measurement_noise_A, config.switch_3ph1ph_delay_s,
config.switch_3ph1ph_cp_state, config.soft_over_current_timeout_ms, config.state_F_after_fault_ms);
config.switch_3ph1ph_cp_state, config.soft_over_current_timeout_ms, config.state_F_after_fault_ms,
config.fail_on_powermeter_errors);

types::iso15118_charger::EVSEID evseid = {config.evse_id, config.evse_id_din};

Expand Down Expand Up @@ -1113,7 +1119,8 @@ void EvseManager::setup_AC_mode() {
charger->setup(config.has_ventilation, Charger::ChargeMode::AC, hlc_enabled, config.ac_hlc_use_5percent,
config.ac_enforce_hlc, true, config.soft_over_current_tolerance_percent,
config.soft_over_current_measurement_noise_A, config.switch_3ph1ph_delay_s,
config.switch_3ph1ph_cp_state, config.soft_over_current_timeout_ms, config.state_F_after_fault_ms);
config.switch_3ph1ph_cp_state, config.soft_over_current_timeout_ms, config.state_F_after_fault_ms,
config.fail_on_powermeter_errors);

types::iso15118_charger::EVSEID evseid = {config.evse_id, config.evse_id_din};

Expand Down
6 changes: 3 additions & 3 deletions modules/EvseManager/EvseManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ struct Conf {
int soft_over_current_timeout_ms;
bool lock_connector_in_state_b;
int state_F_after_fault_ms;
bool fail_on_powermeter_errors;
};

class EvseManager : public Everest::ModuleBase {
Expand Down Expand Up @@ -136,8 +137,7 @@ class EvseManager : public Everest::ModuleBase {
r_imd(std::move(r_imd)),
r_powersupply_DC(std::move(r_powersupply_DC)),
r_store(std::move(r_store)),
config(config) {
}
config(config){};

Everest::MqttProvider& mqtt;
Everest::TelemetryProvider& telemetry;
Expand Down Expand Up @@ -194,7 +194,7 @@ class EvseManager : public Everest::ModuleBase {

const std::vector<std::unique_ptr<powermeterIntf>>& r_powermeter_billing();

// FIXME: this will be removed with proper intergration of BPT on ISO-20
// 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};
Expand Down
Loading