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

Added stackLevel to EnhancedChargingSchedulePeriod #453

Merged
merged 3 commits into from
Feb 15, 2024
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
8 changes: 8 additions & 0 deletions include/ocpp/v16/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <ocpp/common/evse_security_impl.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/smart_charging.hpp>
#include <ocpp/v16/types.hpp>

#include <ocpp/v16/messages/DataTransfer.hpp>
Expand Down Expand Up @@ -153,6 +154,13 @@ class ChargePoint {
/// \return ChargingSchedules of all connectors
std::map<int32_t, ChargingSchedule> get_all_composite_charging_schedules(const int32_t duration_s);

/// \brief Calculates EnhancedChargingSchedule(s) configured by the CSMS of all connectors from now until now +
/// given \p duration_s . EnhancedChargingSchedules contain EnhancedChargingSchedulePeriod(s) that are enhanced by
/// the stackLevel that was provided for the ChargingProfile
/// \param duration_s
/// \return ChargingSchedules of all connectors
std::map<int32_t, EnhancedChargingSchedule> get_all_enhanced_composite_charging_schedules(const int32_t duration_s);

/// \brief Stores the given \p powermeter values for the given \p connector . This function can be called when a new
/// meter value is present.
/// \param connector
Expand Down
7 changes: 7 additions & 0 deletions include/ocpp/v16/charge_point_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,13 @@ class ChargePointImpl : ocpp::ChargingStationBase {
/// \return ChargingSchedules of all connectors
std::map<int32_t, ChargingSchedule> get_all_composite_charging_schedules(const int32_t duration_s);

/// \brief Calculates EnhancedChargingSchedule(s) configured by the CSMS of all connectors from now until now +
/// given \p duration_s . EnhancedChargingSchedules contain EnhancedChargingSchedulePeriod(s) that are enhanced by
/// the stackLevel that was provided for the ChargingProfile
/// \param duration_s
/// \return ChargingSchedules of all connectors
std::map<int32_t, EnhancedChargingSchedule> get_all_enhanced_composite_charging_schedules(const int32_t duration_s);

/// \brief Stores the given \p powermeter values for the given \p connector . This function can be called when a new
/// meter value is present.
/// \param connector
Expand Down
10 changes: 9 additions & 1 deletion include/ocpp/v16/smart_charging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,15 @@ class SmartChargingHandler {
std::vector<ChargingProfile> get_valid_profiles(const ocpp::DateTime& start_time, const ocpp::DateTime& end_time,
const int connector_id);
///
/// \brief Calculates the composite schedule for the given \p valid_profiles and the given \p connector_id .
/// \brief Calculates the enhanced composite schedule for the given \p valid_profiles and the given \p connector_id
///
EnhancedChargingSchedule calculate_enhanced_composite_schedule(std::vector<ChargingProfile> valid_profiles,
const ocpp::DateTime& start_time,
const ocpp::DateTime& end_time,
const int connector_id,
std::optional<ChargingRateUnit> charging_rate_unit);
///
/// \brief Calculates the composite schedule for the given \p valid_profiles and the given \p connector_id
///
ChargingSchedule calculate_composite_schedule(std::vector<ChargingProfile> valid_profiles,
const ocpp::DateTime& start_time, const ocpp::DateTime& end_time,
Expand Down
30 changes: 30 additions & 0 deletions include/ocpp/v16/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,36 @@
Watchdog
};

/// \brief Enhances ChargingSchedulePeriod with stackLevel
struct EnhancedChargingSchedulePeriod {
int32_t startPeriod;

Check notice on line 204 in include/ocpp/v16/types.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/types.hpp#L204

struct member 'EnhancedChargingSchedulePeriod::startPeriod' is never used.
float limit;

Check notice on line 205 in include/ocpp/v16/types.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/types.hpp#L205

struct member 'EnhancedChargingSchedulePeriod::limit' is never used.
std::optional<int32_t> numberPhases;
int32_t stackLevel;

Check notice on line 207 in include/ocpp/v16/types.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/types.hpp#L207

struct member 'EnhancedChargingSchedulePeriod::stackLevel' is never used.
};

/// \brief Conversion from a given EnhancedChargingSchedulePeriod \p k to a given json object \p j
void to_json(json& j, const EnhancedChargingSchedulePeriod& k);

/// \brief Conversion from a given json object \p j to a given EnhancedChargingSchedulePeriod \p k
void from_json(const json& j, EnhancedChargingSchedulePeriod& k);

/// \brief Enhances ChargingSchedule by containing std::vector<EnhancedChargingSchedulePeriods> instead of
/// std::vector<ChargingSchedulePeriod>
struct EnhancedChargingSchedule {
ChargingRateUnit chargingRateUnit;
std::vector<EnhancedChargingSchedulePeriod> chargingSchedulePeriod;

Check notice on line 220 in include/ocpp/v16/types.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/types.hpp#L220

struct member 'EnhancedChargingSchedule::chargingSchedulePeriod' is never used.
std::optional<int32_t> duration;
std::optional<ocpp::DateTime> startSchedule;
std::optional<float> minChargingRate;
};

/// \brief Conversion from a given EnhancedChargingSchedule \p k to a given json object \p j
void to_json(json& j, const EnhancedChargingSchedule& k);

/// \brief Conversion from a given json object \p j to a given EnhancedChargingSchedule \p k
void from_json(const json& j, EnhancedChargingSchedule& k);

} // namespace v16
} // namespace ocpp

Expand Down
6 changes: 5 additions & 1 deletion lib/ocpp/v16/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ DataTransferResponse ChargePoint::data_transfer(const CiString<255>& vendorId,
}

std::map<int32_t, ChargingSchedule> ChargePoint::get_all_composite_charging_schedules(const int32_t duration_s) {

return this->charge_point->get_all_composite_charging_schedules(duration_s);
}

std::map<int32_t, EnhancedChargingSchedule>
ChargePoint::get_all_enhanced_composite_charging_schedules(const int32_t duration_s) {
return this->charge_point->get_all_enhanced_composite_charging_schedules(duration_s);
}

void ChargePoint::on_meter_values(int32_t connector, const Measurement& measurement) {
this->charge_point->on_meter_values(connector, measurement);
}
Expand Down
20 changes: 20 additions & 0 deletions lib/ocpp/v16/charge_point_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2668,6 +2668,26 @@ std::map<int32_t, ChargingSchedule> ChargePointImpl::get_all_composite_charging_
return charging_schedules;
}

std::map<int32_t, EnhancedChargingSchedule>
ChargePointImpl::get_all_enhanced_composite_charging_schedules(const int32_t duration_s) {

std::map<int32_t, EnhancedChargingSchedule> charging_schedules;

for (int connector_id = 0; connector_id <= this->configuration->getNumberOfConnectors(); connector_id++) {
const auto start_time = ocpp::DateTime();
const auto duration = std::chrono::seconds(duration_s);
const auto end_time = ocpp::DateTime(start_time.to_time_point() + duration);

const auto valid_profiles =
this->smart_charging_handler->get_valid_profiles(start_time, end_time, connector_id);
const auto composite_schedule = this->smart_charging_handler->calculate_enhanced_composite_schedule(
valid_profiles, start_time, end_time, connector_id, ChargingRateUnit::A);
charging_schedules[connector_id] = composite_schedule;
}

return charging_schedules;
}

bool ChargePointImpl::is_pnc_enabled() {
return this->configuration->getSupportedFeatureProfilesSet().count(SupportedFeatureProfiles::PnC) and
this->configuration->getISO15118PnCEnabled();
Expand Down
54 changes: 39 additions & 15 deletions lib/ocpp/v16/smart_charging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,24 +170,44 @@ int SmartChargingHandler::get_number_installed_profiles() {
}

ChargingSchedule SmartChargingHandler::calculate_composite_schedule(
std::vector<ChargingProfile> valid_profiles, const ocpp::DateTime& start_time, const ocpp::DateTime& end_time,
const int connector_id, std::optional<ChargingRateUnit> charging_rate_unit) {
const auto enhanced_composite_schedule = this->calculate_enhanced_composite_schedule(
valid_profiles, start_time, end_time, connector_id, charging_rate_unit);
ChargingSchedule composite_schedule;
composite_schedule.chargingRateUnit = enhanced_composite_schedule.chargingRateUnit;
composite_schedule.duration = enhanced_composite_schedule.duration;
composite_schedule.startSchedule = enhanced_composite_schedule.startSchedule;
composite_schedule.minChargingRate = enhanced_composite_schedule.minChargingRate;
for (const auto enhanced_period : enhanced_composite_schedule.chargingSchedulePeriod) {
ChargingSchedulePeriod period;
period.startPeriod = enhanced_period.startPeriod;
period.limit = enhanced_period.limit;
period.numberPhases = enhanced_period.numberPhases;
composite_schedule.chargingSchedulePeriod.push_back(period);
}
return composite_schedule;
}

EnhancedChargingSchedule SmartChargingHandler::calculate_enhanced_composite_schedule(
std::vector<ChargingProfile> valid_profiles, const ocpp::DateTime& start_time, const ocpp::DateTime& end_time,
const int connector_id, std::optional<ChargingRateUnit> charging_rate_unit) {
// return in amps if not given
if (!charging_rate_unit) {
charging_rate_unit.emplace(ChargingRateUnit::A);
}

ChargingSchedule composite_schedule; // the schedule that will be returned
EnhancedChargingSchedule composite_schedule; // the schedule that will be returned
composite_schedule.chargingRateUnit = charging_rate_unit.value();
composite_schedule.duration.emplace(
duration_cast<seconds>(end_time.to_time_point() - start_time.to_time_point()).count());

std::vector<ChargingSchedulePeriod> periods;
std::vector<EnhancedChargingSchedulePeriod> periods;

ocpp::DateTime temp_time(start_time);
ocpp::DateTime last_period_end_time(end_time);
auto current_period_limit = std::numeric_limits<int>::max();
auto lowest_limit_for_this_period = std::numeric_limits<int>::max();
LimitStackLevelPair significant_limit_stack_level_pair = {std::numeric_limits<int>::max(), -1};

// calculate every ChargingSchedulePeriod of result within this while loop
while (duration_cast<seconds>(end_time.to_time_point() - temp_time.to_time_point()).count() > 0) {
Expand Down Expand Up @@ -225,34 +245,38 @@ ChargingSchedule SmartChargingHandler::calculate_composite_schedule(
}
}

int tx_limit;
// if there is a limit with purpose TxProfile it overrules the limit of purpose TxDefaultProfile
if (current_purpose_and_stack_limits.at(ChargingProfilePurposeType::TxProfile).limit !=
std::numeric_limits<int>::max()) {
tx_limit = current_purpose_and_stack_limits.at(ChargingProfilePurposeType::TxProfile).limit;
significant_limit_stack_level_pair =
current_purpose_and_stack_limits.at(ChargingProfilePurposeType::TxProfile);
} else {
tx_limit = current_purpose_and_stack_limits.at(ChargingProfilePurposeType::TxDefaultProfile).limit;
significant_limit_stack_level_pair =
current_purpose_and_stack_limits.at(ChargingProfilePurposeType::TxDefaultProfile);
}

// lowest limit for this period is minimum of ChargePointMaxProfile limit or tx_limit
lowest_limit_for_this_period = std::min(
current_purpose_and_stack_limits.at(ChargingProfilePurposeType::ChargePointMaxProfile).limit, tx_limit);
if (current_purpose_and_stack_limits.at(ChargingProfilePurposeType::ChargePointMaxProfile).limit <
significant_limit_stack_level_pair.limit) {
significant_limit_stack_level_pair =
current_purpose_and_stack_limits.at(ChargingProfilePurposeType::ChargePointMaxProfile);
}

// insert new period to result only if limit changed or period was found
if (lowest_limit_for_this_period != current_period_limit and
lowest_limit_for_this_period != std::numeric_limits<int>::max()) {
if (significant_limit_stack_level_pair.limit != current_period_limit and
significant_limit_stack_level_pair.limit != std::numeric_limits<int>::max()) {

ChargingSchedulePeriod new_period;
EnhancedChargingSchedulePeriod new_period;
const auto start_period =
duration_cast<seconds>(temp_time.to_time_point() - start_time.to_time_point()).count();
new_period.startPeriod = start_period;
new_period.limit =
get_requested_limit(lowest_limit_for_this_period, temp_number_phases, charging_rate_unit.value());
new_period.limit = get_requested_limit(significant_limit_stack_level_pair.limit, temp_number_phases,
charging_rate_unit.value());
new_period.numberPhases = temp_number_phases;
new_period.stackLevel = significant_limit_stack_level_pair.stack_level;
periods.push_back(new_period);

last_period_end_time = temp_period_end_time;
current_period_limit = lowest_limit_for_this_period;
current_period_limit = significant_limit_stack_level_pair.limit;
}
temp_time = this->get_next_temp_time(temp_time, valid_profiles, connector_id);
}
Expand Down
62 changes: 62 additions & 0 deletions lib/ocpp/v16/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,5 +562,67 @@ bool MeasurandWithPhase::operator==(MeasurandWithPhase measurand_with_phase) {
return false;
}

/// \brief Conversion from a given ChargingSchedulePeriod \p k to a given json object \p j
void to_json(json& j, const EnhancedChargingSchedulePeriod& k) {
// the required parts of the message
j = json{{"startPeriod", k.startPeriod}, {"limit", k.limit}, {"stackLevel", k.stackLevel}};
// the optional parts of the message
if (k.numberPhases) {
j["numberPhases"] = k.numberPhases.value();
}
}

/// \brief Conversion from a given json object \p j to a given ChargingSchedulePeriod \p k
void from_json(const json& j, EnhancedChargingSchedulePeriod& k) {
// the required parts of the message
k.startPeriod = j.at("startPeriod");
k.limit = j.at("limit");
k.stackLevel = j.at("stackLevel");

// the optional parts of the message
if (j.contains("numberPhases")) {
k.numberPhases.emplace(j.at("numberPhases"));
}
}

/// \brief Conversion from a given ChargingSchedule \p k to a given json object \p j
void to_json(json& j, const EnhancedChargingSchedule& k) {
// the required parts of the message
j = json{
{"chargingRateUnit", conversions::charging_rate_unit_to_string(k.chargingRateUnit)},
{"chargingSchedulePeriod", k.chargingSchedulePeriod},
};
// the optional parts of the message
if (k.duration) {
j["duration"] = k.duration.value();
}
if (k.startSchedule) {
j["startSchedule"] = k.startSchedule.value().to_rfc3339();
}
if (k.minChargingRate) {
j["minChargingRate"] = k.minChargingRate.value();
}
}

/// \brief Conversion from a given json object \p j to a given ChargingSchedule \p k
void from_json(const json& j, EnhancedChargingSchedule& k) {
// the required parts of the message
k.chargingRateUnit = conversions::string_to_charging_rate_unit(j.at("chargingRateUnit"));
for (auto val : j.at("chargingSchedulePeriod")) {
k.chargingSchedulePeriod.push_back(val);
}

// the optional parts of the message
if (j.contains("duration")) {
k.duration.emplace(j.at("duration"));
}
if (j.contains("startSchedule")) {
k.startSchedule.emplace(j.at("startSchedule").get<std::string>());
}
if (j.contains("minChargingRate")) {
k.minChargingRate.emplace(j.at("minChargingRate"));
}
}

} // namespace v16
} // namespace ocpp
Loading