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

If no metervalues are going to be sent, do not sent a MeterValueRequest or an empty meterValue list in a transaction #187

Merged
merged 1 commit into from
Oct 13, 2023
Merged
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
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 @@ -82,10 +82,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 @@ -186,10 +188,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 @@ -206,14 +212,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 @@ -867,12 +878,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 @@ -1671,11 +1683,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 @@ -1744,7 +1766,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 @@ -1759,12 +1783,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