Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,22 @@
*/
package de.rwth.idsg.steve.ocpp.task;

import de.rwth.idsg.steve.SteveException;
import de.rwth.idsg.steve.ocpp.CommunicationTask;
import de.rwth.idsg.steve.ocpp.OcppVersion;
import de.rwth.idsg.steve.ocpp.task.impl.OcppVersionHandler;
import de.rwth.idsg.steve.ocpp.task.impl.TaskDefinition;
import de.rwth.idsg.steve.repository.ChargingProfileRepository;
import de.rwth.idsg.steve.web.dto.ocpp.RemoteStartTransactionParams;
import ocpp.cp._2015._10.ChargingProfile;
import ocpp.cp._2015._10.ChargingProfilePurposeType;
import org.jspecify.annotations.Nullable;

public class RemoteStartTransactionTask extends CommunicationTask<RemoteStartTransactionParams, String> {
public class RemoteStartTransactionTask
extends CommunicationTask<RemoteStartTransactionTask.RemoteStartTransactionWithProfileParams, String> {

private static final TaskDefinition<RemoteStartTransactionParams, String> TASK_DEFINITION =
TaskDefinition.<RemoteStartTransactionParams, String>builder()
private static final TaskDefinition<RemoteStartTransactionWithProfileParams, String> TASK_DEFINITION =
TaskDefinition.<RemoteStartTransactionWithProfileParams, String>builder()
.versionHandler(
OcppVersion.V_12,
new OcppVersionHandler<>(
Expand All @@ -49,16 +55,62 @@ public class RemoteStartTransactionTask extends CommunicationTask<RemoteStartTra
new OcppVersionHandler<>(
task -> new ocpp.cp._2015._10.RemoteStartTransactionRequest()
.withIdTag(task.getParams().getIdTag())
.withConnectorId(task.getParams().getConnectorId()),
.withConnectorId(task.getParams().getConnectorId())
.withChargingProfile(task.getParams().chargingProfile),
(ocpp.cp._2015._10.RemoteStartTransactionResponse r) ->
r.getStatus().value()))
.build();

public RemoteStartTransactionTask(RemoteStartTransactionParams params) {
super(TASK_DEFINITION, params);
public RemoteStartTransactionTask(
RemoteStartTransactionParams params, ChargingProfileRepository chargingProfileRepository) {
super(
TASK_DEFINITION,
new RemoteStartTransactionWithProfileParams(
params, createChargingProfile(params.getChargingProfilePk(), chargingProfileRepository)));
}

public RemoteStartTransactionTask(
RemoteStartTransactionParams params, String caller, ChargingProfileRepository chargingProfileRepository) {
super(
TASK_DEFINITION,
new RemoteStartTransactionWithProfileParams(
params, createChargingProfile(params.getChargingProfilePk(), chargingProfileRepository)),
caller);
}

public static class RemoteStartTransactionWithProfileParams extends RemoteStartTransactionParams {
private final ocpp.cp._2015._10.@Nullable ChargingProfile chargingProfile;

public RemoteStartTransactionWithProfileParams(
RemoteStartTransactionParams params, ocpp.cp._2015._10.@Nullable ChargingProfile chargingProfile) {
super();
this.setIdTag(params.getIdTag());
this.setConnectorId(params.getConnectorId());
this.chargingProfile = chargingProfile;
}

@Override
public @Nullable Integer getChargingProfilePk() {
if (chargingProfile == null) {
return null;
}
return chargingProfile.getChargingProfileId();
}
}

public RemoteStartTransactionTask(RemoteStartTransactionParams params, String caller) {
super(TASK_DEFINITION, params, caller);
private static @Nullable ChargingProfile createChargingProfile(
@Nullable Integer chargingProfilePk, ChargingProfileRepository chargingProfileRepository) {
if (chargingProfilePk == null) {
return null;
}
de.rwth.idsg.steve.repository.dto.ChargingProfile.Details details = chargingProfileRepository
.getDetails(chargingProfilePk)
.orElseThrow(() ->
new SteveException.BadRequest("ChargingProfile with PK " + chargingProfilePk + " not found"));
ocpp.cp._2015._10.ChargingProfile chargingProfile = SetChargingProfileTask.mapToOcpp(details, null);
if (chargingProfile.getChargingProfilePurpose() != ChargingProfilePurposeType.TX_PROFILE) {
throw new SteveException.BadRequest("ChargingProfilePurposeType is not TX_PROFILE");
}
return chargingProfile;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ public OcppCallback<String> createDefaultCallback() {
@Override
public void success(String chargeBoxId, String statusValue) {
addNewResponse(chargeBoxId, statusValue);
if ("Accepted".equalsIgnoreCase(statusValue)) {
var purpose = ChargingProfilePurposeType.fromValue(details.getChargingProfilePurpose());
if ("Accepted".equalsIgnoreCase(statusValue) && ChargingProfilePurposeType.TX_PROFILE != purpose) {
repo.setProfile(details.getChargingProfilePk(), chargeBoxId, params.getConnectorId());
}
}
Expand All @@ -110,6 +111,14 @@ public void failed(String chargeBoxId, Exception e) {

private static SetChargingProfileRequest buildRequestFromDb(
SetChargingProfileParams params, ChargingProfile.Details details) {
var ocppProfile = mapToOcpp(details, params.getTransactionId());

return new SetChargingProfileRequest()
.withConnectorId(params.getConnectorId())
.withCsChargingProfiles(ocppProfile);
}

public static ocpp.cp._2015._10.ChargingProfile mapToOcpp(ChargingProfile.Details details, Integer transactionId) {
var schedulePeriods = details.getPeriods().stream()
.map(k -> {
ChargingSchedulePeriod p = new ChargingSchedulePeriod();
Expand All @@ -127,8 +136,9 @@ private static SetChargingProfileRequest buildRequestFromDb(
.withMinChargingRate(details.getMinChargingRate())
.withChargingSchedulePeriod(schedulePeriods);

var ocppProfile = new ocpp.cp._2015._10.ChargingProfile()
return new ocpp.cp._2015._10.ChargingProfile()
.withChargingProfileId(details.getChargingProfilePk())
.withTransactionId(transactionId)
.withStackLevel(details.getStackLevel())
.withChargingProfilePurpose(ChargingProfilePurposeType.fromValue(details.getChargingProfilePurpose()))
.withChargingProfileKind(ChargingProfileKindType.fromValue(details.getChargingProfileKind()))
Expand All @@ -138,10 +148,6 @@ private static SetChargingProfileRequest buildRequestFromDb(
.withValidFrom(toOffsetDateTime(details.getValidFrom()))
.withValidTo(toOffsetDateTime(details.getValidTo()))
.withChargingSchedule(schedule);

return new SetChargingProfileRequest()
.withConnectorId(params.getConnectorId())
.withCsChargingProfiles(ocppProfile);
}

private static void checkAdditionalConstraints(SetChargingProfileRequest request) {
Expand All @@ -158,6 +164,16 @@ private static void checkAdditionalConstraints(SetChargingProfileRequest request
throw new SteveException.InternalError(
"TxProfile should only be set at Charge Point ConnectorId > 0");
}

if (ChargingProfilePurposeType.TX_PROFILE == purpose
&& request.getCsChargingProfiles().getTransactionId() == null) {
throw new SteveException.InternalError("transaction id is required for TxProfile");
}

if (ChargingProfilePurposeType.TX_PROFILE != purpose
&& request.getCsChargingProfiles().getTransactionId() != null) {
throw new SteveException.InternalError("transaction id should only be set for TxProfile");
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,14 @@ public final int updateFirmware(UpdateFirmwareParams params, OcppCallback<String
// -------------------------------------------------------------------------
@SafeVarargs
public final int remoteStartTransaction(RemoteStartTransactionParams params, OcppCallback<String>... callbacks) {
RemoteStartTransactionTask task = new RemoteStartTransactionTask(params);
RemoteStartTransactionTask task = new RemoteStartTransactionTask(params, chargingProfileRepository);
return addRemoteStartTask(task, callbacks);
}

@SafeVarargs
public final int remoteStartTransaction(
RemoteStartTransactionParams params, String caller, OcppCallback<String>... callbacks) {
RemoteStartTransactionTask task = new RemoteStartTransactionTask(params, caller);
RemoteStartTransactionTask task = new RemoteStartTransactionTask(params, caller, chargingProfileRepository);
return addRemoteStartTask(task, callbacks);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Positive;

/**
* @author Sevket Goekay <sevketgokay@gmail.com>
* @since 01.01.2015
*/
@Getter
@Setter
public class RemoteStartTransactionParams extends SingleChargePointSelect {

@Min(value = 0, message = "Connector ID must be at least {value}") @Nullable private Integer connectorId;

@NotBlank(message = "User ID Tag is required") @IdTag
@Setter
private String idTag;

@Positive private @Nullable Integer chargingProfilePk;

/**
* Not for a specific connector, when frontend sends the value 0.
* This corresponds to not to include the connector id parameter in OCPP request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ public class SetChargingProfileParams extends MultipleChargePointSelect {
@NotNull @Min(value = 0, message = "Connector ID must be at least {value}") private Integer connectorId;

@NotNull @Positive private Integer chargingProfilePk;

@Positive private Integer transactionId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ public class Ocpp12Controller {
// Helpers
// -------------------------------------------------------------------------

/**
* https://github.com/steve-community/steve/issues/1759
* used to create form in order to send charging profile within remote start tx for ocpp 1.6.
*/
protected void setCommonAttributesForRemoteStartTx(Model model) {
// nothing to do for versions below 1.6
}

protected void setCommonAttributesForTx(Model model) {
setCommonAttributes(model);
}
Expand Down Expand Up @@ -150,6 +158,7 @@ public String getGetDiag(Model model) {
public String getRemoteStartTx(Model model) {
setCommonAttributesForTx(model);
setActiveUserIdTagList(model);
setCommonAttributesForRemoteStartTx(model);
model.addAttribute(PARAMS, new RemoteStartTransactionParams());
return getPrefix() + REMOTE_START_TX_PATH;
}
Expand Down Expand Up @@ -233,6 +242,7 @@ public String postRemoteStartTx(
if (result.hasErrors()) {
setCommonAttributesForTx(model);
setActiveUserIdTagList(model);
setCommonAttributesForRemoteStartTx(model);
return getPrefix() + REMOTE_START_TX_PATH;
}
return REDIRECT_TASKS_PATH + chargePointServiceClient.remoteStartTransaction(params);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public Ocpp16Controller(
// Helpers
// -------------------------------------------------------------------------

protected void setCommonAttributesForRemoteStartTx(Model model) {
model.addAttribute("profileForRemoteStartTx", Boolean.TRUE);
model.addAttribute("profileList", chargingProfileRepository.getBasicInfo());
}

@Override
protected void setCommonAttributesForTx(Model model) {
model.addAttribute("cpList", chargePointHelperService.getChargePoints(OcppVersion.V_16));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
</form:select>
</td>
</tr>
<c:if test="${profileForRemoteStartTx}">
<tr>
<td>Charging Profile ID:</td>
<td>
<form:select path="chargingProfilePk">
<form:option value="">-- Empty --</form:option>
<form:options items="${profileList}" itemLabel="itemDescription" itemValue="chargingProfilePk"/>
</form:select>
</td>
</tr>
</c:if>
<tr><td></td><td><div class="submit-button"><input type="submit" value="Perform"></div></td></tr>
</table>
</form:form>
</form:form>
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,18 @@
</tr>
<tr>
<td>Connector ID (integer):</td>
<td><form:input path="connectorId" placeholder="0 = charge point as a whole"/></td>
<td>
<form:input path="connectorId" type="number" inputmode="numeric" min="0" step="1" placeholder="0 = charge point as a whole"/>
<form:errors path="connectorId" cssClass="error"/>
</td>
</tr>
<tr>
<td>Transaction ID (integer):</td>
<td>
<form:input path="transactionId" type="number" inputmode="numeric" min="1" step="1" placeholder="only necessary for TxProfile"/>
<form:errors path="transactionId" cssClass="error"/>
</td>
</tr>
<tr><td></td><td><div class="submit-button"><input type="submit" value="Perform"></div></td></tr>
</table>
</form:form>
</form:form>
Loading