Skip to content

Commit d84e47c

Browse files
committed
implement ExtendedTriggerMessage
1 parent cb36fe7 commit d84e47c

29 files changed

+278
-50
lines changed

src/main/java/de/rwth/idsg/steve/ocpp/ChargePointServiceInvokerImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import de.rwth.idsg.steve.ocpp.task.ClearCacheTask;
2626
import de.rwth.idsg.steve.ocpp.task.ClearChargingProfileTask;
2727
import de.rwth.idsg.steve.ocpp.task.DataTransferTask;
28+
import de.rwth.idsg.steve.ocpp.task.ExtendedTriggerMessageTask;
2829
import de.rwth.idsg.steve.ocpp.task.GetCompositeScheduleTask;
2930
import de.rwth.idsg.steve.ocpp.task.GetConfigurationTask;
3031
import de.rwth.idsg.steve.ocpp.task.GetDiagnosticsTask;
@@ -235,4 +236,14 @@ public void triggerMessage(ChargePointSelect cp, TriggerMessageTask task) {
235236
chargePointServiceJsonInvoker.runPipeline(cp, task);
236237
}
237238
}
239+
240+
// -------------------------------------------------------------------------
241+
// "Improved security for OCPP 1.6-J" additions. Only for JSON
242+
// -------------------------------------------------------------------------
243+
244+
public void extendedTriggerMessage(ChargePointSelect cp, ExtendedTriggerMessageTask task) {
245+
if (cp.isJson()) {
246+
chargePointServiceJsonInvoker.runPipeline(cp, task);
247+
}
248+
}
238249
}

src/main/java/de/rwth/idsg/steve/ocpp/task/ExtendedTriggerMessageTask.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
import de.rwth.idsg.steve.ocpp.Ocpp16AndAboveTask;
2222
import de.rwth.idsg.steve.ocpp.OcppCallback;
2323
import de.rwth.idsg.steve.web.dto.ocpp.ExtendedTriggerMessageParams;
24-
25-
import jakarta.xml.ws.AsyncHandler;
2624
import ocpp._2022._02.security.ExtendedTriggerMessage;
2725
import ocpp._2022._02.security.ExtendedTriggerMessageResponse;
2826

27+
import jakarta.xml.ws.AsyncHandler;
28+
2929
public class ExtendedTriggerMessageTask extends Ocpp16AndAboveTask<ExtendedTriggerMessageParams, String> {
3030

3131
public ExtendedTriggerMessageTask(ExtendedTriggerMessageParams params) {
@@ -40,24 +40,16 @@ public OcppCallback<String> defaultCallback() {
4040
@Override
4141
public ExtendedTriggerMessage getOcpp16Request() {
4242
var request = new ExtendedTriggerMessage();
43-
request.setRequestedMessage(
44-
ExtendedTriggerMessage.MessageTriggerEnumType.valueOf(params.getRequestedMessage().toString())
45-
);
46-
47-
if (params.getConnectorId() != null) {
48-
request.setConnectorId(params.getConnectorId());
49-
}
50-
43+
request.setRequestedMessage(params.getTriggerMessage());
44+
request.setConnectorId(params.getConnectorId());
5145
return request;
5246
}
5347

5448
@Override
5549
public AsyncHandler<ExtendedTriggerMessageResponse> getOcpp16Handler(String chargeBoxId) {
5650
return res -> {
5751
try {
58-
var response = res.get();
59-
var status = response.getStatus() != null ? response.getStatus().toString() : "Unknown";
60-
success(chargeBoxId, status);
52+
success(chargeBoxId, res.get().getStatus().value());
6153
} catch (Exception e) {
6254
failed(chargeBoxId, e);
6355
}

src/main/java/de/rwth/idsg/steve/repository/dto/ChargePointSelect.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,8 @@ public boolean isEndpointAddressSet() {
4747
public boolean isSoap() {
4848
return OcppTransport.SOAP == ocppProtocol.getTransport();
4949
}
50+
51+
public boolean isJson() {
52+
return OcppTransport.JSON == ocppProtocol.getTransport();
53+
}
5054
}

src/main/java/de/rwth/idsg/steve/service/ChargePointService.java

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -268,34 +268,44 @@ public List<ChargePointSelect> getChargePointsWithIds(OcppVersion version, List<
268268
return getChargePoints(version, Collections.singletonList(RegistrationStatus.ACCEPTED), chargeBoxIdFilter);
269269
}
270270

271-
private List<ChargePointSelect> getChargePoints(OcppVersion version, List<RegistrationStatus> inStatusFilter,
272-
List<String> chargeBoxIdFilter) {
273-
List<ChargePointSelect> returnList = new ArrayList<>();
274-
275-
// soap stations
276-
{
277-
List<String> statusFilter = inStatusFilter.stream()
278-
.map(RegistrationStatus::value)
279-
.collect(Collectors.toList());
280-
281-
var soapProtocol = version.toProtocol(OcppTransport.SOAP);
282-
283-
returnList.addAll(chargePointRepository.getChargePointSelect(soapProtocol, statusFilter, chargeBoxIdFilter));
284-
}
285-
286-
// json stations
287-
{
288-
SessionContextStore sessionStore = sessionContextStoreHolder.getOrCreate(version);
271+
public List<ChargePointSelect> getChargePoints(OcppProtocol protocol,
272+
List<RegistrationStatus> inStatusFilter,
273+
List<String> chargeBoxIdFilter) {
274+
OcppVersion version = protocol.getVersion();
275+
OcppTransport transport = protocol.getTransport();
276+
277+
switch (transport) {
278+
case SOAP -> {
279+
List<String> statusFilter = inStatusFilter.stream()
280+
.map(RegistrationStatus::value)
281+
.collect(Collectors.toList());
282+
283+
var soapProtocol = version.toProtocol(OcppTransport.SOAP);
284+
return chargePointRepository.getChargePointSelect(soapProtocol, statusFilter, chargeBoxIdFilter);
285+
}
286+
case JSON -> {
287+
SessionContextStore sessionStore = sessionContextStoreHolder.getOrCreate(version);
289288

290-
List<String> chargeBoxIdList = CollectionUtils.isEmpty(chargeBoxIdFilter)
291-
? sessionStore.getChargeBoxIdList()
292-
: sessionStore.getChargeBoxIdList().stream().filter(chargeBoxIdFilter::contains).toList();
289+
List<String> chargeBoxIdList = CollectionUtils.isEmpty(chargeBoxIdFilter)
290+
? sessionStore.getChargeBoxIdList()
291+
: sessionStore.getChargeBoxIdList().stream().filter(chargeBoxIdFilter::contains).toList();
293292

294-
var jsonProtocol = version.toProtocol(OcppTransport.JSON);
293+
var jsonProtocol = version.toProtocol(OcppTransport.JSON);
295294

296-
chargeBoxIdList.forEach(chargeBoxId -> returnList.add(new ChargePointSelect(jsonProtocol, chargeBoxId)));
295+
return chargeBoxIdList.stream()
296+
.map(chargeBoxId -> new ChargePointSelect(jsonProtocol, chargeBoxId))
297+
.toList();
298+
}
299+
default -> throw new IllegalStateException("Unexpected value: " + transport);
297300
}
301+
}
298302

303+
private List<ChargePointSelect> getChargePoints(OcppVersion version,
304+
List<RegistrationStatus> inStatusFilter,
305+
List<String> chargeBoxIdFilter) {
306+
List<ChargePointSelect> returnList = new ArrayList<>();
307+
returnList.addAll(getChargePoints(version.toProtocol(OcppTransport.SOAP), inStatusFilter, chargeBoxIdFilter));
308+
returnList.addAll(getChargePoints(version.toProtocol(OcppTransport.JSON), inStatusFilter, chargeBoxIdFilter));
299309
return returnList;
300310
}
301311

src/main/java/de/rwth/idsg/steve/service/ChargePointServiceClient.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import de.rwth.idsg.steve.ocpp.task.ClearCacheTask;
2828
import de.rwth.idsg.steve.ocpp.task.ClearChargingProfileTask;
2929
import de.rwth.idsg.steve.ocpp.task.DataTransferTask;
30+
import de.rwth.idsg.steve.ocpp.task.ExtendedTriggerMessageTask;
3031
import de.rwth.idsg.steve.ocpp.task.GetCompositeScheduleTask;
3132
import de.rwth.idsg.steve.ocpp.task.GetConfigurationTask;
3233
import de.rwth.idsg.steve.ocpp.task.GetDiagnosticsTask;
@@ -54,6 +55,7 @@
5455
import de.rwth.idsg.steve.web.dto.ocpp.ChangeConfigurationParams;
5556
import de.rwth.idsg.steve.web.dto.ocpp.ClearChargingProfileParams;
5657
import de.rwth.idsg.steve.web.dto.ocpp.DataTransferParams;
58+
import de.rwth.idsg.steve.web.dto.ocpp.ExtendedTriggerMessageParams;
5759
import de.rwth.idsg.steve.web.dto.ocpp.GetCompositeScheduleParams;
5860
import de.rwth.idsg.steve.web.dto.ocpp.GetConfigurationParams;
5961
import de.rwth.idsg.steve.web.dto.ocpp.GetDiagnosticsParams;
@@ -450,4 +452,23 @@ public final int getCompositeSchedule(GetCompositeScheduleParams params,
450452
return taskStore.add(task);
451453
}
452454

455+
// -------------------------------------------------------------------------
456+
// "Improved security for OCPP 1.6-J" additions
457+
// -------------------------------------------------------------------------
458+
459+
@SafeVarargs
460+
public final int extendedTriggerMessage(ExtendedTriggerMessageParams params,
461+
OcppCallback<String>... callbacks) {
462+
ExtendedTriggerMessageTask task = new ExtendedTriggerMessageTask(params);
463+
464+
for (var callback : callbacks) {
465+
task.addCallback(callback);
466+
}
467+
468+
BackgroundService.with(taskExecutor)
469+
.forEach(task.getParams().getChargePointSelectList())
470+
.execute(c -> invoker.extendedTriggerMessage(c, task));
471+
472+
return taskStore.add(task);
473+
}
453474
}

src/main/java/de/rwth/idsg/steve/web/controller/Ocpp16Controller.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@
5353
* @author Sevket Goekay <[email protected]>
5454
* @since 15.03.2018
5555
*/
56-
@Controller
57-
@RequestMapping(value = "/manager/operations/v1.6")
56+
//@Controller
57+
//@RequestMapping(value = "/manager/operations/v1.6")
5858
public class Ocpp16Controller extends Ocpp15Controller {
5959

6060
private final ChargingProfileRepository chargingProfileRepository;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
3+
* Copyright (C) 2013-2025 SteVe Community Team
4+
* All Rights Reserved.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
package de.rwth.idsg.steve.web.controller;
20+
21+
import de.rwth.idsg.steve.ocpp.OcppProtocol;
22+
import de.rwth.idsg.steve.repository.ChargingProfileRepository;
23+
import de.rwth.idsg.steve.service.ChargePointService;
24+
import de.rwth.idsg.steve.service.ChargePointServiceClient;
25+
import de.rwth.idsg.steve.service.OcppTagService;
26+
import de.rwth.idsg.steve.web.dto.ocpp.ExtendedTriggerMessageParams;
27+
import ocpp.cs._2015._10.RegistrationStatus;
28+
import org.springframework.stereotype.Controller;
29+
import org.springframework.ui.Model;
30+
import org.springframework.validation.BindingResult;
31+
import org.springframework.web.bind.annotation.ModelAttribute;
32+
import org.springframework.web.bind.annotation.RequestMapping;
33+
import org.springframework.web.bind.annotation.RequestMethod;
34+
35+
import jakarta.validation.Valid;
36+
import java.util.Arrays;
37+
import java.util.Collections;
38+
39+
/**
40+
* Improved security for OCPP 1.6-J
41+
*/
42+
@Controller
43+
@RequestMapping(value = "/manager/operations/v1.6")
44+
public class Ocpp16ImprovedSecurityController extends Ocpp16Controller {
45+
46+
public Ocpp16ImprovedSecurityController(OcppTagService ocppTagService,
47+
ChargePointService chargePointService,
48+
ChargePointServiceClient chargePointServiceClient,
49+
ChargingProfileRepository chargingProfileRepository) {
50+
super(ocppTagService, chargePointService, chargePointServiceClient, chargingProfileRepository);
51+
}
52+
53+
private static final String EXTENDED_TRIGGER_MESSAGE_PATH = "/ExtendedTriggerMessage";
54+
55+
/**
56+
* "Improved security for OCPP 1.6-J" white paper defines new operations only for JSON. Therefore, our station
57+
* selection should only contain JSON.
58+
*/
59+
protected void setCommonAttributesForImprovedSecurity(Model model) {
60+
var inStatusFilter = Arrays.asList(RegistrationStatus.ACCEPTED, RegistrationStatus.PENDING);
61+
var chargePoints = chargePointService.getChargePoints(OcppProtocol.V_16_JSON, inStatusFilter, Collections.emptyList());
62+
63+
model.addAttribute("cpList", chargePoints);
64+
model.addAttribute("opVersion", "v1.6");
65+
}
66+
67+
@RequestMapping(value = EXTENDED_TRIGGER_MESSAGE_PATH, method = RequestMethod.GET)
68+
public String getExtendedTriggerMessage(Model model) {
69+
setCommonAttributesForImprovedSecurity(model);
70+
model.addAttribute(PARAMS, new ExtendedTriggerMessageParams());
71+
return getPrefix() + EXTENDED_TRIGGER_MESSAGE_PATH;
72+
}
73+
74+
@RequestMapping(value = EXTENDED_TRIGGER_MESSAGE_PATH, method = RequestMethod.POST)
75+
public String postTriggerMessage(@Valid @ModelAttribute(PARAMS) ExtendedTriggerMessageParams params,
76+
BindingResult result, Model model) {
77+
if (result.hasErrors()) {
78+
setCommonAttributesForImprovedSecurity(model);
79+
return getPrefix() + EXTENDED_TRIGGER_MESSAGE_PATH;
80+
}
81+
return REDIRECT_TASKS_PATH + chargePointServiceClient.extendedTriggerMessage(params);
82+
}
83+
84+
85+
}

src/main/java/de/rwth/idsg/steve/web/dto/ocpp/ExtendedTriggerMessageParams.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import lombok.Getter;
2222
import lombok.Setter;
23+
import ocpp._2022._02.security.ExtendedTriggerMessage;
2324

2425
import jakarta.validation.constraints.Min;
2526
import jakarta.validation.constraints.NotNull;
@@ -28,19 +29,9 @@
2829
@Getter
2930
public class ExtendedTriggerMessageParams extends MultipleChargePointSelect {
3031

31-
@NotNull(message = "Requested message is required")
32-
private MessageTriggerEnumType requestedMessage;
32+
@NotNull(message = "Trigger Message is required")
33+
private ExtendedTriggerMessage.MessageTriggerEnumType triggerMessage;
3334

3435
@Min(value = 0, message = "Connector ID must be at least {value}")
3536
private Integer connectorId;
36-
37-
public enum MessageTriggerEnumType {
38-
BootNotification,
39-
LogStatusNotification,
40-
FirmwareStatusNotification,
41-
Heartbeat,
42-
MeterValues,
43-
SignChargePointCertificate,
44-
StatusNotification
45-
}
4637
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<%--
2+
3+
SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
4+
Copyright (C) 2013-2025 SteVe Community Team
5+
All Rights Reserved.
6+
7+
This program is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <https://www.gnu.org/licenses/>.
19+
20+
--%>
21+
<form:form action="${ctxPath}/manager/operations/${opVersion}/ExtendedTriggerMessage" modelAttribute="params">
22+
<section><span>Charge Points with OCPP ${opVersion}</span></section>
23+
<%@ include file="../00-cp-multiple.jsp" %>
24+
<section><span>Parameters</span></section>
25+
<table class="userInput">
26+
<tr>
27+
<td>Trigger Message:</td>
28+
<td>
29+
<form:select path="triggerMessage">
30+
<form:options items="${triggerMessage}" itemLabel="value"/>
31+
</form:select>
32+
</td>
33+
</tr>
34+
<tr>
35+
<td>Connector ID (integer):</td>
36+
<td><form:input path="connectorId" placeholder="if empty, charge point as a whole"/></td>
37+
</tr>
38+
<tr>
39+
<td></td><td><div class="submit-button"><input type="submit" value="Perform"></div></td>
40+
</tr>
41+
</table>
42+
</form:form>

src/main/webapp/WEB-INF/views/op16/CancelReservation.jsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<li><a href="${ctxPath}/manager/operations/${opVersion}/GetCompositeSchedule">Get Composite Schedule</a></li>
5050
<li><a href="${ctxPath}/manager/operations/${opVersion}/ClearChargingProfile">Clear Charging Profile</a></li>
5151
<li><a href="${ctxPath}/manager/operations/${opVersion}/SetChargingProfile">Set Charging Profile</a></li>
52+
<li><a href="${ctxPath}/manager/operations/${opVersion}/ExtendedTriggerMessage"><i>Extended Trigger Message</i></a></li>
5253
</ul>
5354
</div>
5455
<div class="op16-content">

0 commit comments

Comments
 (0)