Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
14 changes: 7 additions & 7 deletions doc/ocpp_201_status.md
Original file line number Diff line number Diff line change
Expand Up @@ -1266,7 +1266,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir
| K01.FR.40 | ✅ | `Absolute`/`Recurring` profiles without `startSchedule` fields are rejected. |
| K01.FR.41 | ✅ | `Relative` profiles with `startSchedule` fields are rejected. |
| K01.FR.42 | ⛽️ | |
| K01.FR.43 | | Open question to OCA - https://oca.causewaynow.com/wg/OCA-TWG/mail/thread/4254 |
| K01.FR.43 | | Open question to OCA - <https://oca.causewaynow.com/wg/OCA-TWG/mail/thread/4254> |
| K01.FR.44 | ✅ | We reject invalid profiles instead of modifying and accepting them. |
| K01.FR.45 | ✅ | We reject invalid profiles instead of modifying and accepting them. |
| K01.FR.46 | ⛽️ | K08 |
Expand Down Expand Up @@ -1381,7 +1381,7 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir
| K11.FR.01 | | |
| K11.FR.02 | | |
| K11.FR.03 | | |
| K11.FR.04 | | |
| K11.FR.04 | | |
| K11.FR.05 | | |
| K11.FR.06 | | |

Expand All @@ -1390,18 +1390,18 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir
| ID | Status | Remark |
|-----------|--------|--------|
| K12.FR.01 | | |
| K12.FR.02 | | |
| K12.FR.03 | | |
| K12.FR.04 | | |
| K12.FR.02 | | |
| K12.FR.03 | | |
| K12.FR.04 | | The spec does not define what we should do when the source given is CSO. The system currently throws and exception. |
| K12.FR.05 | | |

## SmartCharging - Reset / Release External Charging Limit

| ID | Status | Remark |
|-----------|--------|--------|
| K13.FR.01 | | |
| K13.FR.02 | | |
| K13.FR.03 | | |
| K13.FR.02 | | |
| K13.FR.03 | | |

## SmartCharging - External Charging Limit with Local Controller

Expand Down
26 changes: 26 additions & 0 deletions include/ocpp/v201/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,25 @@ class ChargePointInterface {
///
virtual void on_variable_changed(const SetVariableData& set_variable_data) = 0;

/// \brief Notifies the ChargePoint that a new external limit has been set. This may send a
/// NotifyChargingLimitRequest if the \p percentage_delta is greater than our LimitChangeSignificance.
/// \param evse_id ID of the EVSE with the external limit
/// \param limit the new external limit
/// \param percentage_delta the percent changed from the existing limits
/// \param source the source of the external limit (NOTE: Should never be CSO)
virtual void on_external_limits_changed(const std::variant<ConstantChargingLimit, ChargingSchedule>& limit,
double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) = 0;

/// \brief Notifies the ChargePoint that an external limit has been cleared.
/// This shall send a ClearedChargingLimitRequest when called.
// This may send TransactionEventRequest if the \p percentage_delta is greater than our LimitChangeSignificance.
/// \param percentage_delta the percent changed from the existing limits
/// \param source the source of the external limit
/// \param evse_id if provided checks for transactions on the provided evse
virtual void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) = 0;

/// \brief Data transfer mechanism initiated by charger
/// \param vendorId
/// \param messageId
Expand Down Expand Up @@ -819,6 +838,13 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa

void on_variable_changed(const SetVariableData& set_variable_data) override;

void on_external_limits_changed(const std::variant<ConstantChargingLimit, ChargingSchedule>& limit,
double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) override;

void on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) override;

std::optional<DataTransferResponse> data_transfer_req(const CiString<255>& vendorId,
const std::optional<CiString<50>>& messageId,
const std::optional<json>& data) override;
Expand Down
44 changes: 44 additions & 0 deletions include/ocpp/v201/smart_charging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@
#ifndef OCPP_V201_SMART_CHARGING_HPP
#define OCPP_V201_SMART_CHARGING_HPP

#include "ocpp/v201/comparators.hpp"
#include "ocpp/v201/messages/ClearedChargingLimit.hpp"
#include "ocpp/v201/messages/TransactionEvent.hpp"
#include <limits>
#include <memory>
#include <optional>
#include <utility>
#include <variant>

#include <ocpp/v201/database_handler.hpp>
#include <ocpp/v201/device_model.hpp>
#include <ocpp/v201/evse_manager.hpp>
#include <ocpp/v201/messages/ClearChargingProfile.hpp>
#include <ocpp/v201/messages/GetChargingProfiles.hpp>
#include <ocpp/v201/messages/NotifyChargingLimit.hpp>
#include <ocpp/v201/messages/SetChargingProfile.hpp>
#include <ocpp/v201/ocpp_enums.hpp>
#include <ocpp/v201/ocpp_types.hpp>
Expand Down Expand Up @@ -56,6 +63,13 @@
RequestStartTransactionRequest
};

struct ConstantChargingLimit {
float limit;

Check notice on line 67 in include/ocpp/v201/smart_charging.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/smart_charging.hpp#L67

struct member 'ConstantChargingLimit::limit' is never used.
ChargingRateUnitEnum charging_rate_unit;
};

bool operator==(const ConstantChargingLimit& a, const ConstantChargingLimit& b);

namespace conversions {
/// \brief Converts the given ProfileValidationResultEnum \p e to human readable string
/// \returns a string representation of the ProfileValidationResultEnum
Expand Down Expand Up @@ -97,6 +111,15 @@
const ocpp::DateTime& start_time,
const ocpp::DateTime& end_time, const int32_t evse_id,
std::optional<ChargingRateUnitEnum> charging_rate_unit) = 0;

virtual std::optional<std::pair<NotifyChargingLimitRequest, std::vector<TransactionEventRequest>>>
handle_external_limits_changed(const std::variant<ConstantChargingLimit, ChargingSchedule>& limit,
double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) const = 0;

virtual std::optional<std::pair<ClearedChargingLimitRequest, std::vector<TransactionEventRequest>>>
handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) const = 0;
};

/// \brief This class handles and maintains incoming ChargingProfiles and contains the logic
Expand Down Expand Up @@ -165,6 +188,23 @@
const int32_t evse_id,
std::optional<ChargingRateUnitEnum> charging_rate_unit) override;

///
/// \brief Determines whether or not we should notify the CSMS of a changed external limit
/// based on \p percentage_delta and builds the notification.
///
std::optional<std::pair<NotifyChargingLimitRequest, std::vector<TransactionEventRequest>>>
handle_external_limits_changed(const std::variant<ConstantChargingLimit, ChargingSchedule>& limit,
double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) const override;

///
/// \brief Determines whether or not we should notify the CSMS of a cleared external limit
/// based on \p percentage_delta and builds the notification.
///
std::optional<std::pair<ClearedChargingLimitRequest, std::vector<TransactionEventRequest>>>
handle_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) const override;

protected:
///
/// \brief validates the existence of the given \p evse_id according to the specification
Expand Down Expand Up @@ -218,6 +258,10 @@
std::vector<ChargingProfile> get_valid_profiles_for_evse(int32_t evse_id);
void conform_validity_periods(ChargingProfile& profile) const;
CurrentPhaseType get_current_phase_type(const std::optional<EvseInterface*> evse_opt) const;
TransactionEventRequest create_transaction_event_request(std::unique_ptr<EnhancedTransaction>& tx) const;
bool process_evses_with_active_transactions(const bool limit_change_significance_exceeded,
std::vector<TransactionEventRequest>& transaction_event_requests,
std::optional<int32_t> evse_id) const;
};

} // namespace ocpp::v201
Expand Down
45 changes: 45 additions & 0 deletions lib/ocpp/v201/charge_point.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest

#include <cstdint>
#include <ocpp/common/types.hpp>
#include <ocpp/v201/charge_point.hpp>
#include <ocpp/v201/ctrlr_component_variables.hpp>
Expand Down Expand Up @@ -1013,6 +1014,50 @@ void ChargePoint::on_variable_changed(const SetVariableData& set_variable_data)
this->handle_variable_changed(set_variable_data);
}

void ChargePoint::on_external_limits_changed(const std::variant<ConstantChargingLimit, ChargingSchedule>& limit,
double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) {
auto request =
this->smart_charging_handler->handle_external_limits_changed(limit, percentage_delta, source, evse_id);
if (request.has_value()) {
auto [cleared_charging_limit_request, transaction_event_requests] = request.value();

ocpp::Call<NotifyChargingLimitRequest> call(cleared_charging_limit_request,
this->message_queue->createMessageId());
this->send<NotifyChargingLimitRequest>(call);

if (transaction_event_requests.size() > 0) {
for (auto transaction_event_request : transaction_event_requests) {
ocpp::Call<TransactionEventRequest> call(transaction_event_request,
this->message_queue->createMessageId());
this->send<TransactionEventRequest>(call);
}
}
}
}

void ChargePoint::on_external_limit_cleared(double percentage_delta, ChargingLimitSourceEnum source,
std::optional<int32_t> evse_id) {
auto request = this->smart_charging_handler->handle_external_limit_cleared(percentage_delta, source, evse_id);

if (request.has_value()) {

auto [cleared_charging_limit_request, transaction_event_requests] = request.value();

ocpp::Call<ClearedChargingLimitRequest> call(cleared_charging_limit_request,
this->message_queue->createMessageId());
this->send<ClearedChargingLimitRequest>(call);

if (transaction_event_requests.size() > 0) {
for (auto transaction_event_request : transaction_event_requests) {
ocpp::Call<TransactionEventRequest> call(transaction_event_request,
this->message_queue->createMessageId());
this->send<TransactionEventRequest>(call);
}
}
}
}

bool ChargePoint::send(CallError call_error) {
this->message_queue->push(call_error);
return true;
Expand Down
Loading
Loading