Skip to content

Commit

Permalink
Added K01.FR06 duplication check for dates
Browse files Browse the repository at this point in the history
Signed-off-by: Coury Richards <[email protected]>
  • Loading branch information
couryrr-afs committed Apr 22, 2024
1 parent 8d4e7a4 commit c2aab4e
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 71 deletions.
2 changes: 1 addition & 1 deletion doc/ocpp_201_status.md
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ This document contains the status of which OCPP 2.0.1 numbered requirements have
| K01.FR.03 | | |
| K01.FR.04 | :white_check_mark: | |
| K01.FR.05 | | |
| K01.FR.06 | | |
| K01.FR.06 | :white_check_mark: | |
| K01.FR.07 | | |
| K01.FR.08 | | |
| K01.FR.09 | | |
Expand Down
8 changes: 7 additions & 1 deletion include/ocpp/v201/smart_charging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ enum class ProfileValidationResultEnum {
ChargingSchedulePeriodInvalidPhaseToUse,
ChargingSchedulePeriodUnsupportedNumberPhases,
ChargingSchedulePeriodExtraneousPhaseValues,
DuplicateTxDefaultProfileFound
DuplicateTxDefaultProfileFound,
DuplicateProfileValidityPeriod
};

namespace conversions {
Expand Down Expand Up @@ -83,6 +84,11 @@ class SmartChargingHandler {
///
void add_profile(int32_t evse_id, ChargingProfile& profile);

///
/// \brief Checks a given \p profile and associated \p evse_id validFrom and validTo range
///
bool is_overlapping_validity_period(int evse_id, ChargingProfile profile) const;

private:
std::vector<ChargingProfile> get_evse_specific_tx_default_profiles() const;
std::vector<ChargingProfile> get_station_wide_tx_default_profiles() const;
Expand Down
92 changes: 91 additions & 1 deletion lib/ocpp/v201/smart_charging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ ProfileValidationResultEnum SmartChargingHandler::validate_evse_exists(int32_t e
ProfileValidationResultEnum SmartChargingHandler::validate_tx_default_profile(const ChargingProfile& profile,
int32_t evse_id) const {
auto profiles = evse_id == 0 ? get_evse_specific_tx_default_profiles() : get_station_wide_tx_default_profiles();

if (is_overlapping_validity_period(evse_id, profile)) {
return ProfileValidationResultEnum::DuplicateProfileValidityPeriod;
}

for (auto candidate : profiles) {
if (candidate.stackLevel == profile.stackLevel) {
if (candidate.id != profile.id) {
Expand Down Expand Up @@ -112,6 +117,7 @@ ProfileValidationResultEnum SmartChargingHandler::validate_tx_profile(const Char
candidateProfile.stackLevel == profile.stackLevel;
});
};

if (std::any_of(charging_profiles.begin(), charging_profiles.end(), conflicts_with)) {
return ProfileValidationResultEnum::TxProfileConflictingStackLevel;
}
Expand All @@ -125,10 +131,12 @@ ProfileValidationResultEnum SmartChargingHandler::validate_tx_profile(const Char
* - K01.FR.43
* - K01.FR.48
*/

ProfileValidationResultEnum
SmartChargingHandler::validate_profile_schedules(ChargingProfile& profile,
std::optional<EvseInterface*> evse_opt) const {
for (ChargingSchedule& schedule : profile.chargingSchedule) {
for (auto& schedule : profile.chargingSchedule) {

// A schedule must have at least one chargingSchedulePeriod
if (schedule.chargingSchedulePeriod.empty()) {
return ProfileValidationResultEnum::ChargingProfileNoChargingSchedulePeriods;
Expand Down Expand Up @@ -224,4 +232,86 @@ std::vector<ChargingProfile> SmartChargingHandler::get_station_wide_tx_default_p
return station_wide_tx_default_profiles;
}

bool SmartChargingHandler::is_overlapping_validity_period(int candidate_evse_id,
ChargingProfile candidate_profile) const {
if (candidate_profile.chargingProfilePurpose == ChargingProfilePurposeEnum::TxProfile) {
// This only applies to non TxProfile types.
return false;
}

auto conflicts_with = [candidate_evse_id, &candidate_profile](
const std::pair<int32_t, std::vector<ChargingProfile>>& existing_profiles) {
auto existing_evse_id = existing_profiles.first;
if (existing_evse_id == candidate_evse_id) {
return std::any_of(
existing_profiles.second.begin(), existing_profiles.second.end(),
[&candidate_profile](const ChargingProfile& existing_profile) {
if (existing_profile.stackLevel == candidate_profile.stackLevel &&
existing_profile.chargingProfileKind == candidate_profile.chargingProfileKind &&
existing_profile.id != candidate_profile.id) {

// Existing profile last forever should be updated to replace
if (!existing_profile.validFrom.has_value() && !existing_profile.validTo.has_value()) {
return true; // reject
}

// Cannot accept new profile that last forever when there is an existing profile
if (!candidate_profile.validFrom.has_value() && !candidate_profile.validTo.has_value()) {
return true; // reject
}

// Existing has validFrom only
if (existing_profile.validFrom.has_value() && !existing_profile.validTo.has_value()) {
if (candidate_profile.validFrom.has_value() && !candidate_profile.validTo.has_value()) {
return true; // reject
}
if (candidate_profile.validTo.has_value() &&
candidate_profile.validTo <= existing_profile.validFrom) {
return true; // reject
}
}

// Existing has validTo only
if (!existing_profile.validFrom.has_value() && existing_profile.validTo.has_value()) {
if (!candidate_profile.validFrom.has_value() && candidate_profile.validTo.has_value()) {
return true; // reject
}
if (candidate_profile.validFrom.has_value() &&
candidate_profile.validFrom >= existing_profile.validTo) {
return true; // reject
}
}

// Case Everything is set
if (existing_profile.validFrom.has_value() && existing_profile.validTo.has_value()) {
if (!candidate_profile.validFrom.has_value() && !candidate_profile.validTo.has_value()) {
return true;
}

// Is not after
if (candidate_profile.validFrom.has_value() &&
candidate_profile.validFrom <= existing_profile.validTo) {
return true; // reject
} else {
return false;
}

// Is not before
if (candidate_profile.validTo.has_value() &&
candidate_profile.validTo >= existing_profile.validFrom) {
return true; // reject
} else {
return false;
}
}
}
return false;
});
}
return false;
};

return std::any_of(charging_profiles.begin(), charging_profiles.end(), conflicts_with);
}

} // namespace ocpp::v201
Loading

0 comments on commit c2aab4e

Please sign in to comment.