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

Feature/notify ev charging needs #93

Merged
merged 12 commits into from
Mar 17, 2025
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.14)

project(iso15118
VERSION 0.5.0
VERSION 0.5.1
DESCRIPTION "iso15118 library suite"
LANGUAGES CXX C
)
Expand Down
1 change: 1 addition & 0 deletions include/iso15118/d20/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct EvseSetupConfig {
std::vector<ControlMobilityNeedsModes> control_mobility_modes;
};

// This should only have EVSE information
struct SessionConfig {
explicit SessionConfig(EvseSetupConfig);

Expand Down
4 changes: 4 additions & 0 deletions include/iso15118/d20/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "config.hpp"
#include "control_event.hpp"
#include "ev_session_info.hpp"
#include "session.hpp"

namespace iso15118::d20 {
Expand Down Expand Up @@ -96,6 +97,9 @@ class Context {

SessionConfig session_config;

// Contains the EV received data
EVSessionInfo session_ev_info;

bool session_stopped{false};

private:
Expand Down
15 changes: 15 additions & 0 deletions include/iso15118/d20/ev_session_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 Pionix GmbH and Contributors to EVerest
#pragma once

#include <iso15118/session/feedback.hpp>

namespace iso15118::d20 {

// Holds information reported by the EV
struct EVSessionInfo {
session::feedback::EvTransferLimits ev_transfer_limits;
session::feedback::EvSEControlMode ev_control_mode;
};

} // namespace iso15118::d20
31 changes: 25 additions & 6 deletions include/iso15118/session/feedback.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
#include <string>
#include <variant>

#include <iso15118/d20/limits.hpp>
#include <iso15118/message/dc_charge_loop.hpp>
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
#include <iso15118/message/schedule_exchange.hpp>
#include <iso15118/message/type.hpp>

namespace iso15118::session {

namespace dt = message_20::datatypes;

namespace feedback {

enum class Signal {
Expand All @@ -34,14 +39,18 @@ struct DcMaximumLimits {
float power{NAN};
};

using PresentVoltage = message_20::datatypes::RationalNumber;
using PresentVoltage = dt::RationalNumber;
using MeterInfoRequested = bool;
using DcReqControlMode = std::variant<
message_20::datatypes::Scheduled_DC_CLReqControlMode, message_20::datatypes::BPT_Scheduled_DC_CLReqControlMode,
message_20::datatypes::Dynamic_DC_CLReqControlMode, message_20::datatypes::BPT_Dynamic_DC_CLReqControlMode>;
using DcReqControlMode = std::variant<dt::Scheduled_DC_CLReqControlMode, dt::BPT_Scheduled_DC_CLReqControlMode,
dt::Dynamic_DC_CLReqControlMode, dt::BPT_Dynamic_DC_CLReqControlMode>;

using DcChargeLoopReq = std::variant<DcReqControlMode, dt::DisplayParameters, PresentVoltage, MeterInfoRequested>;

// TODO(ioan): preparation for AC limits
using EvseTransferLimits = std::variant<d20::DcTransferLimits>;

using DcChargeLoopReq =
std::variant<DcReqControlMode, message_20::datatypes::DisplayParameters, PresentVoltage, MeterInfoRequested>;
using EvTransferLimits = std::variant<dt::DC_CPDReqEnergyTransferMode, dt::BPT_DC_CPDReqEnergyTransferMode>;
using EvSEControlMode = std::variant<dt::Dynamic_SEReqControlMode, dt::Scheduled_SEReqControlMode>;

struct Callbacks {
std::function<void(Signal)> signal;
Expand All @@ -51,6 +60,11 @@ struct Callbacks {
std::function<void(const message_20::Type&)> v2g_message;
std::function<void(const std::string&)> evccid;
std::function<void(const std::string&)> selected_protocol;

std::function<void(const dt::ServiceCategory&, const std::optional<dt::AcConnector>&, const dt::ControlMode&,
const dt::MobilityNeedsMode&, const EvseTransferLimits&, const EvTransferLimits&,
const EvSEControlMode&)>
notify_ev_charging_needs;
};

} // namespace feedback
Expand All @@ -67,6 +81,11 @@ class Feedback {
void evcc_id(const std::string&) const;
void selected_protocol(const std::string&) const;

void notify_ev_charging_needs(const dt::ServiceCategory&, const std::optional<dt::AcConnector>&,
const dt::ControlMode&, const dt::MobilityNeedsMode&,
const feedback::EvseTransferLimits&, const feedback::EvTransferLimits&,
const feedback::EvSEControlMode&) const;

private:
feedback::Callbacks callbacks;
};
Expand Down
14 changes: 7 additions & 7 deletions src/iso15118/d20/state/dc_charge_parameter_discovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ template <> void convert(DC_ModeRes& out, const d20::DcTransferLimits& in) {
}

template <> void convert(BPT_DC_ModeRes& out, const d20::DcTransferLimits& in) {
out.max_charge_power = in.charge_limits.power.max;
out.min_charge_power = in.charge_limits.power.min;
out.max_charge_current = in.charge_limits.current.max;
out.min_charge_current = in.charge_limits.current.min;
out.max_voltage = in.voltage.max;
out.min_voltage = in.voltage.min;
out.power_ramp_limit = in.power_ramp_limit;
convert(static_cast<DC_ModeRes&>(out), in);

if (in.discharge_limits.has_value()) {
auto& discharge_limits = in.discharge_limits.value();
Expand Down Expand Up @@ -111,13 +105,19 @@ Result DC_ChargeParameterDiscovery::feed(Event ev) {
dc_max_limits.power = dt::from_RationalNumber(mode->max_charge_power);

logf_info("Max charge current %fA", dt::from_RationalNumber(mode->max_charge_current));

// Set EV transfer limits
m_ctx.session_ev_info.ev_transfer_limits.emplace<DC_ModeReq>(*mode);
} else if (const auto* mode = std::get_if<BPT_DC_ModeReq>(&req->transfer_mode)) {
dc_max_limits.current = dt::from_RationalNumber(mode->max_charge_current);
dc_max_limits.voltage = dt::from_RationalNumber(mode->max_voltage);
dc_max_limits.power = dt::from_RationalNumber(mode->max_charge_power);

logf_info("Max charge current %fA", dt::from_RationalNumber(mode->max_charge_current));
logf_info("Max discharge current %fA", dt::from_RationalNumber(mode->max_discharge_current));

// Set EV transfer limits
m_ctx.session_ev_info.ev_transfer_limits.emplace<BPT_DC_ModeReq>(*mode);
}

const auto res = handle_request(*req, m_ctx.session, m_ctx.session_config.dc_limits);
Expand Down
21 changes: 20 additions & 1 deletion src/iso15118/d20/state/schedule_exchange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,32 @@ Result ScheduleExchange::feed(Event ev) {

dt::RationalNumber max_charge_power = {0, 0};

const auto selected_energy_service = m_ctx.session.get_selected_services().selected_energy_service;
const auto& selected_services = m_ctx.session.get_selected_services();
const auto selected_energy_service = selected_services.selected_energy_service;

if (selected_energy_service == dt::ServiceCategory::DC or
selected_energy_service == dt::ServiceCategory::DC_BPT) {
max_charge_power = m_ctx.session_config.dc_limits.charge_limits.power.max;
}

// We will pass the raw data to the listener, the
// listener will construct the full required type
std::optional<dt::AcConnector> ac_connector{};
if (std::holds_alternative<dt::AcConnector>(selected_services.selected_connector)) {
ac_connector = std::get<dt::AcConnector>(selected_services.selected_connector);
}

// TODO(ioan): prepare for AC transfer limits
const session::feedback::EvseTransferLimits& evse_limits = m_ctx.session_config.dc_limits;
const session::feedback::EvTransferLimits& ev_limits = m_ctx.session_ev_info.ev_transfer_limits;

const auto& control_mode = req->control_mode;

// Send the charging feedback
m_ctx.feedback.notify_ev_charging_needs(
selected_energy_service, ac_connector, selected_services.selected_control_mode,
selected_services.selected_mobility_needs_mode, evse_limits, ev_limits, control_mode);

const auto res = handle_request(*req, m_ctx.session, max_charge_power, dynamic_parameters);

m_ctx.respond(res);
Expand Down
11 changes: 11 additions & 0 deletions src/iso15118/session/feedback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,15 @@ void Feedback::selected_protocol(const std::string& selected_protocol) const {
call_if_available(callbacks.selected_protocol, selected_protocol);
}

void Feedback::notify_ev_charging_needs(const dt::ServiceCategory& service_category,
const std::optional<dt::AcConnector>& ac_connector,
const dt::ControlMode& control_mode,
const dt::MobilityNeedsMode& mobility_needs_mode,
const feedback::EvseTransferLimits& evse_limits,
const feedback::EvTransferLimits& ev_limits,
const feedback::EvSEControlMode& ev_control_mode) const {
call_if_available(callbacks.notify_ev_charging_needs, service_category, ac_connector, control_mode,
mobility_needs_mode, evse_limits, ev_limits, ev_control_mode);
}

} // namespace iso15118::session