Skip to content

Commit

Permalink
Added stackLevel to EnhancedChargingSchedulePeriod and implemented re…
Browse files Browse the repository at this point in the history
…spective requirements for introduction of the new types

Signed-off-by: pietfried <[email protected]>
  • Loading branch information
Pietfried committed Feb 2, 2024
1 parent 36df4f0 commit 0e81145
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 21 deletions.
3 changes: 2 additions & 1 deletion 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 @@ -151,7 +152,7 @@ class ChargePoint {
/// duration_s
/// \param duration_s
/// \return ChargingSchedules of all connectors
std::map<int32_t, ChargingSchedule> get_all_composite_charging_schedules(const int32_t duration_s);
std::map<int32_t, EnhancedChargingSchedule> get_all_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.
Expand Down
2 changes: 1 addition & 1 deletion include/ocpp/v16/charge_point_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ class ChargePointImpl : ocpp::ChargingStationBase {
/// duration_s
/// \param duration_s
/// \return ChargingSchedules of all connectors
std::map<int32_t, ChargingSchedule> get_all_composite_charging_schedules(const int32_t duration_s);
std::map<int32_t, EnhancedChargingSchedule> get_all_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.
Expand Down
33 changes: 33 additions & 0 deletions include/ocpp/v16/smart_charging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,33 @@ struct PeriodDateTimePair {
ocpp::DateTime end_time;
};

struct EnhancedChargingSchedulePeriod {
int32_t startPeriod;

Check notice on line 37 in include/ocpp/v16/smart_charging.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/smart_charging.hpp#L37

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

Check notice on line 38 in include/ocpp/v16/smart_charging.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/smart_charging.hpp#L38

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

Check notice on line 40 in include/ocpp/v16/smart_charging.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/smart_charging.hpp#L40

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);

struct EnhancedChargingSchedule {
ChargingRateUnit chargingRateUnit;
std::vector<EnhancedChargingSchedulePeriod> chargingSchedulePeriod;

Check notice on line 51 in include/ocpp/v16/smart_charging.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v16/smart_charging.hpp#L51

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);

/// \brief This class handles and maintains incoming ChargingProfiles and contains the logic
/// to calculate the composite schedules
class SmartChargingHandler {
Expand Down Expand Up @@ -127,6 +154,12 @@ class SmartChargingHandler {
///
/// \brief Calculates the 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);

ChargingSchedule calculate_composite_schedule(std::vector<ChargingProfile> valid_profiles,
const ocpp::DateTime& start_time, const ocpp::DateTime& end_time,
const int connector_id,
Expand Down
3 changes: 2 additions & 1 deletion lib/ocpp/v16/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ DataTransferResponse ChargePoint::data_transfer(const CiString<255>& vendorId,
return this->charge_point->data_transfer(vendorId, messageId, data);
}

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

return this->charge_point->get_all_composite_charging_schedules(duration_s);
}
Expand Down
7 changes: 4 additions & 3 deletions lib/ocpp/v16/charge_point_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2648,9 +2648,10 @@ IdTagInfo ChargePointImpl::authorize_id_token(CiString<20> idTag) {
return id_tag_info;
}

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

std::map<int32_t, ChargingSchedule> charging_schedules;
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();
Expand All @@ -2659,7 +2660,7 @@ std::map<int32_t, ChargingSchedule> ChargePointImpl::get_all_composite_charging_

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_composite_schedule(
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;
}
Expand Down
120 changes: 105 additions & 15 deletions lib/ocpp/v16/smart_charging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,72 @@ using namespace std::chrono;
namespace ocpp {
namespace v16 {

/// \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"));
}
}

bool validate_schedule(const ChargingSchedule& schedule, const int charging_schedule_max_periods,
const std::vector<ChargingRateUnit>& charging_schedule_allowed_charging_rate_units) {

Expand Down Expand Up @@ -170,24 +236,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 +311,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

0 comments on commit 0e81145

Please sign in to comment.