Skip to content

Commit

Permalink
If no metervalues are going to be sent, do not sent a MeterValueReque…
Browse files Browse the repository at this point in the history
…st or an empty meterValue list in a transaction

Signed-off-by: Marc Emmers <[email protected]>
  • Loading branch information
marcemmers committed Oct 2, 2023
1 parent 1cb0999 commit da013de
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 26 deletions.
4 changes: 4 additions & 0 deletions include/ocpp/v201/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ namespace utils {
/// \brief std::vector<MeasurandEnum> of the configured AlignedDataMeasurands
std::vector<MeasurandEnum> get_measurands_vec(const std::string& measurands_csv);

///\brief This function determines if any of the \p measurands is present in the \p _meter_value at all
///\return True if any measurand is found, false otherwise
bool meter_value_has_any_measurand(const MeterValue& _meter_value, const std::vector<MeasurandEnum>& measurands);

/// \brief Applies the given \p measurands to the given \p _meter_value . The returned meter value will only contain
/// SampledValues which measurand is listed in the given \param measurands . If no measurand is set for the
/// SampledValue, the SampledValue will also be omitted.
Expand Down
70 changes: 49 additions & 21 deletions lib/ocpp/v201/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ ChargePoint::ChargePoint(const std::map<int32_t, int32_t>& evse_connector_struct
_meter_value, utils::get_measurands_vec(this->device_model->get_value<std::string>(
ControllerComponentVariables::SampledDataTxUpdatedMeasurands)));

this->transaction_event_req(TransactionEventEnum::Updated, DateTime(), transaction,
TriggerReasonEnum::MeterValuePeriodic, seq_no, std::nullopt, std::nullopt,
std::nullopt, std::vector<MeterValue>(1, filtered_meter_value), std::nullopt,
this->is_offline(), reservation_id);
if (!filtered_meter_value.sampledValue.empty()) {
this->transaction_event_req(TransactionEventEnum::Updated, DateTime(), transaction,
TriggerReasonEnum::MeterValuePeriodic, seq_no, std::nullopt, std::nullopt,
std::nullopt, std::vector<MeterValue>(1, filtered_meter_value),
std::nullopt, this->is_offline(), reservation_id);
}
};

this->evses.insert(
Expand Down Expand Up @@ -185,10 +187,14 @@ void ChargePoint::on_transaction_started(
auto evse = this->evses.at(evse_id)->get_evse_info();
evse.connectorId.emplace(connector_id);

std::optional<std::vector<MeterValue>> opt_meter_value;
if (!meter_value.sampledValue.empty()) {
opt_meter_value.emplace(1, meter_value);
}

this->transaction_event_req(TransactionEventEnum::Started, timestamp, transaction, trigger_reason,
enhanced_transaction->get_seq_no(), std::nullopt, evse, enhanced_transaction->id_token,
std::vector<MeterValue>(1, meter_value), std::nullopt, this->is_offline(),
reservation_id);
opt_meter_value, std::nullopt, this->is_offline(), reservation_id);
}

void ChargePoint::on_transaction_finished(const int32_t evse_id, const DateTime& timestamp,
Expand All @@ -205,14 +211,19 @@ void ChargePoint::on_transaction_finished(const int32_t evse_id, const DateTime&

this->evses.at(evse_id)->close_transaction(timestamp, meter_stop, reason);
const auto transaction = enhanced_transaction->get_transaction();
const auto meter_values = utils::get_meter_values_with_measurands_and_interval_applied(
auto meter_values = std::make_optional(utils::get_meter_values_with_measurands_and_interval_applied(
enhanced_transaction->meter_values,
utils::get_measurands_vec(
this->device_model->get_value<std::string>(ControllerComponentVariables::AlignedDataTxEndedMeasurands)),
utils::get_measurands_vec(
this->device_model->get_value<std::string>(ControllerComponentVariables::SampledDataTxEndedMeasurands)),
this->device_model->get_value<int>(ControllerComponentVariables::AlignedDataTxEndedInterval),
this->device_model->get_value<int>(ControllerComponentVariables::SampledDataTxEndedInterval));
this->device_model->get_value<int>(ControllerComponentVariables::SampledDataTxEndedInterval)));

if (meter_values.value().empty()) {
meter_values.reset();
}

const auto seq_no = enhanced_transaction->get_seq_no();
this->evses.at(evse_id)->release_transaction();

Expand Down Expand Up @@ -863,12 +874,13 @@ void ChargePoint::update_aligned_data_interval() {
// add meter value to transaction meter values
const auto& enhanced_transaction = evse->get_transaction();
enhanced_transaction->meter_values.push_back(_meter_value);

this->transaction_event_req(
TransactionEventEnum::Updated, DateTime(), enhanced_transaction->get_transaction(),
TriggerReasonEnum::MeterValueClock, enhanced_transaction->get_seq_no(), std::nullopt,
std::nullopt, std::nullopt, std::vector<MeterValue>(1, meter_value), std::nullopt,
this->is_offline(), std::nullopt);
if (!meter_value.sampledValue.empty()) {
this->transaction_event_req(
TransactionEventEnum::Updated, DateTime(), enhanced_transaction->get_transaction(),
TriggerReasonEnum::MeterValueClock, enhanced_transaction->get_seq_no(), std::nullopt,
std::nullopt, std::nullopt, std::vector<MeterValue>(1, meter_value), std::nullopt,
this->is_offline(), std::nullopt);
}
} else if (!evse->has_active_transaction() and
this->device_model
->get_optional_value<bool>(ControllerComponentVariables::AlignedDataSendDuringIdle)
Expand Down Expand Up @@ -1661,11 +1673,21 @@ void ChargePoint::handle_trigger_message(Call<TriggerMessageRequest> call) {

case MessageTriggerEnum::MeterValues:
if (msg.evse.has_value()) {
if (evse_ptr != nullptr) {
if (evse_ptr != nullptr and
utils::meter_value_has_any_measurand(
evse_ptr->get_meter_value(), utils::get_measurands_vec(this->device_model->get_value<std::string>(
ControllerComponentVariables::AlignedDataMeasurands)))) {
response.status = TriggerMessageStatusEnum::Accepted;
}
} else {
response.status = TriggerMessageStatusEnum::Accepted;
auto measurands = utils::get_measurands_vec(this->device_model->get_value<std::string>(
ControllerComponentVariables::SampledDataTxUpdatedMeasurands));
for (auto const& [evse_id, evse] : this->evses) {
if (utils::meter_value_has_any_measurand(evse->get_meter_value(), measurands)) {
response.status = TriggerMessageStatusEnum::Accepted;
break;
}
}
}
break;

Expand Down Expand Up @@ -1734,7 +1756,9 @@ void ChargePoint::handle_trigger_message(Call<TriggerMessageRequest> call) {
get_latest_meter_value_filtered(evse.get_meter_value(), ReadingContextEnum::Trigger,
ControllerComponentVariables::AlignedDataMeasurands);

this->meter_values_req(evse_id, std::vector<ocpp::v201::MeterValue>(1, meter_value));
if (!meter_value.sampledValue.empty()) {
this->meter_values_req(evse_id, std::vector<ocpp::v201::MeterValue>(1, meter_value));
}
};
send_evse_message(send_meter_value);
} break;
Expand All @@ -1749,12 +1773,16 @@ void ChargePoint::handle_trigger_message(Call<TriggerMessageRequest> call) {
get_latest_meter_value_filtered(evse.get_meter_value(), ReadingContextEnum::Trigger,
ControllerComponentVariables::SampledDataTxUpdatedMeasurands);

std::optional<std::vector<MeterValue>> opt_meter_value;
if (!meter_value.sampledValue.empty()) {
opt_meter_value.emplace(1, meter_value);
}
const auto& enhanced_transaction = evse.get_transaction();

this->transaction_event_req(
TransactionEventEnum::Updated, DateTime(), enhanced_transaction->get_transaction(),
TriggerReasonEnum::Trigger, enhanced_transaction->get_seq_no(), std::nullopt, std::nullopt,
std::nullopt, std::vector<MeterValue>(1, meter_value), std::nullopt, this->is_offline(), std::nullopt);
this->transaction_event_req(TransactionEventEnum::Updated, DateTime(),
enhanced_transaction->get_transaction(), TriggerReasonEnum::Trigger,
enhanced_transaction->get_seq_no(), std::nullopt, std::nullopt, std::nullopt,
opt_meter_value, std::nullopt, this->is_offline(), std::nullopt);
};
send_evse_message(send_transaction);
} break;
Expand Down
22 changes: 17 additions & 5 deletions lib/ocpp/v201/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <everest/logging.hpp>

#include <algorithm>

#include <ocpp/common/utils.hpp>
#include <ocpp/v201/utils.hpp>

Expand All @@ -24,6 +26,13 @@ std::vector<MeasurandEnum> get_measurands_vec(const std::string& measurands_csv)
return measurands;
}

bool meter_value_has_any_measurand(const MeterValue& _meter_value, const std::vector<MeasurandEnum>& measurands) {
auto compare = [](const SampledValue& a, MeasurandEnum b) { return a.measurand == b; };

return std::find_first_of(_meter_value.sampledValue.begin(), _meter_value.sampledValue.end(), measurands.begin(),
measurands.end(), compare) != _meter_value.sampledValue.end();
}

MeterValue get_meter_value_with_measurands_applied(const MeterValue& _meter_value,
const std::vector<MeasurandEnum>& measurands) {
auto meter_value = _meter_value;
Expand Down Expand Up @@ -61,14 +70,16 @@ get_meter_values_with_measurands_and_interval_applied(const std::vector<MeterVal
for (const auto& meter_value : _meter_values) {
if (!meter_value.sampledValue.empty() and meter_value.sampledValue.at(0).context.has_value()) {
if ((meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Transaction_Begin or
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Transaction_End) or
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Interruption_Begin or
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Interruption_End) {
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Transaction_End or
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Interruption_Begin or
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Interruption_End) and
meter_value_has_any_measurand(meter_value, sample_measurands)) {
meter_values.push_back(get_meter_value_with_measurands_applied(meter_value, sample_measurands));
}
// ReadingContext is Sample_Clock so aligned_interval applies
else if (aligned_interval > 0 and
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Sample_Clock) {
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Sample_Clock and
meter_value_has_any_measurand(meter_value, aligned_measurands)) {
if (meter_value.timestamp.to_time_point() > next_aligned_timepoint) {
meter_values.push_back(get_meter_value_with_measurands_applied(meter_value, aligned_measurands));
next_aligned_timepoint =
Expand All @@ -77,7 +88,8 @@ get_meter_values_with_measurands_and_interval_applied(const std::vector<MeterVal
}
// ReadingContext is Sample_Periodic so sampled_interval applies
else if (sampled_interval > 0 and
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Sample_Periodic) {
meter_value.sampledValue.at(0).context.value() == ReadingContextEnum::Sample_Periodic and
meter_value_has_any_measurand(meter_value, sample_measurands)) {
if (meter_value.timestamp.to_time_point() > next_sampled_timepoint) {
meter_values.push_back(get_meter_value_with_measurands_applied(meter_value, sample_measurands));
next_sampled_timepoint =
Expand Down

0 comments on commit da013de

Please sign in to comment.