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

WebApi of remote start, remote stop and connector status #1291

Open
wants to merge 58 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
be40edd
set webapi.value in dev
Oct 20, 2023
9d79bdd
add constructor with "caller" value at tasks RemoteStart, RemoteStop …
Oct 20, 2023
d2f54b5
ChargePointRepository: add method getChargePointSelect(String ChageBo…
Oct 20, 2023
cdcb3ee
TransactionRepository: add methods getActiveTransactionId(String char…
Oct 20, 2023
3a3e575
TaskOverview: added swagger.annotations
Oct 20, 2023
08d7fa6
ChargePointService12_Client: add methods which uses new task construc…
Oct 20, 2023
9b580be
Added a first draft of RemoteStartStopREstController, also added data…
Oct 20, 2023
1771e16
Removed tailing spaces
Oct 20, 2023
7417a9e
ConnectorStatusForm: added ApiModelProperty annotation;
Oct 20, 2023
59b31cc
OcppJsonStatus: added ApiModelProperty annotation and JasonIgnor anno…
Oct 20, 2023
bf14cb1
ConnectorStatus: added ApiModelProperty annotation to all fields and …
Oct 20, 2023
55ac2ec
no functional changes
Oct 20, 2023
7fc9c5b
added dto list of connector status for Api
Oct 20, 2023
c39fafa
added connector REST controller
Oct 20, 2023
5a04018
RemoteStartStopController: methode postRemoteStartTx now checks if th…
Oct 25, 2023
ed42990
RemoteStartStopController: moved the task related methods to the new …
Oct 25, 2023
0e724a4
TaskReskController: removed unused import BadRequest...
Oct 25, 2023
9a58541
style
Oct 25, 2023
41017aa
removed unused dto ApiConnectorList
Oct 25, 2023
9b708c8
ApiTaskInfo: removed unused/out commented imports
Oct 25, 2023
e09d14c
REmoteStartStopREstController: added check for active tasks on charge…
Oct 25, 2023
5517cd1
add dto ApiConnectorList
Oct 25, 2023
bc02600
ConnectorRestController: rename method
Oct 25, 2023
770c594
ApiConnectorList: removed unnessesary semicolon
Oct 25, 2023
b5211f7
ApiChargePointStart: correct ApiModelProperty value
Nov 2, 2023
8a56922
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Nov 2, 2023
6b77e92
ConnectorStatusForm add menber for Strategy of listing the connector
Nov 5, 2023
4c01d02
HomeController & ConnectorRestController: option to choose between Pr…
Nov 5, 2023
703867b
connectorStatus.jsp: add query field for strategy the connector listing
Nov 5, 2023
d41e059
style improvement
Nov 6, 2023
5de4edf
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Nov 28, 2023
86cef45
typo and trailing spaces
Dec 6, 2023
875e4fa
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Dec 13, 2023
9908064
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Dec 24, 2023
de45bb3
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Jan 15, 2024
b358166
TaskRestController: changed address to /api/v1/tasks;
Jan 16, 2024
cb7576d
Update license headers
Jan 16, 2024
f087287
getActiveTransactionId(String chargeBox, Integer connectorId) method,…
Jan 23, 2024
85ccc66
TransactionRepository: add method getTransaction(int transactionPk); …
Jan 23, 2024
b46859a
RemoteStartStopRestController adapt to methode changes at Transaction…
Jan 23, 2024
a790ef6
RemoteStartStopRestController: changed style of switch case
Jan 23, 2024
b3da4c3
TransactionRepository: methode getTransaction(int transactionPk) usin…
Jan 23, 2024
52c07da
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Feb 1, 2024
c30d163
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Feb 6, 2024
83efc74
smaller style improvements
Feb 6, 2024
a2dbd95
RemoteStartStopController: removed trailing spaces
Feb 6, 2024
7a34ce7
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Feb 19, 2024
7aaa690
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Mar 28, 2024
c7e795d
Resolve Conflicts: Caused by removing the flag firstArrivingMeterValu…
fnkbsi Apr 3, 2024
e13a6aa
Merge branch 'master' into ApiRemoteStartStop
fnkbsi Apr 3, 2024
aec19e3
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Apr 19, 2024
7c0c773
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi May 13, 2024
fd4f789
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Jun 19, 2024
bc6c41c
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Oct 2, 2024
4d4cdbb
switch from swagger to oas
fnkbsi Oct 7, 2024
9bf3de7
WebUserService: set the api_password at the first start (if no web_us…
fnkbsi Oct 7, 2024
d8f1cd8
Merge branch 'steve-community:master' into ApiRemoteStartStop
fnkbsi Oct 9, 2024
3184086
Merge branch 'master' into ApiRemoteStartStop
fnkbsi Nov 8, 2024
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
4 changes: 4 additions & 0 deletions src/main/java/de/rwth/idsg/steve/ocpp/CommunicationTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public CommunicationTask(OcppVersion ocppVersion, S params) {
this(ocppVersion, params, TaskOrigin.INTERNAL, "SteVe");
}

public CommunicationTask(OcppVersion ocppVersion, S params, String caller) {
this(ocppVersion, params, TaskOrigin.EXTERNAL, caller);
}

/**
* Do not expose the constructor, make it package-private
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public RemoteStartTransactionTask(OcppVersion ocppVersion, RemoteStartTransactio
super(ocppVersion, params);
}

public RemoteStartTransactionTask(OcppVersion ocppVersion, RemoteStartTransactionParams params, String caller) {
super(ocppVersion, params, caller);
}

@Override
public OcppCallback<String> defaultCallback() {
return new StringOcppCallback();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public RemoteStopTransactionTask(OcppVersion ocppVersion, RemoteStopTransactionP
super(ocppVersion, params);
}

public RemoteStopTransactionTask(OcppVersion ocppVersion, RemoteStopTransactionParams params, String caller) {
super(ocppVersion, params, caller);
}

@Override
public OcppCallback<String> defaultCallback() {
return new StringOcppCallback();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public UnlockConnectorTask(OcppVersion ocppVersion, UnlockConnectorParams params
super(ocppVersion, params);
}

public UnlockConnectorTask(OcppVersion ocppVersion, UnlockConnectorParams params, String caller) {
super(ocppVersion, params, caller);
}

@Override
public OcppCallback<String> defaultCallback() {
return new StringOcppCallback();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ default List<ChargePointSelect> getChargePointSelect(OcppProtocol protocol, List
return getChargePointSelect(protocol, inStatusFilter, Collections.emptyList());
}

List<ChargePointSelect> getChargePointSelect(String chageBoxID);

List<String> getChargeBoxIds();
Map<String, Integer> getChargeBoxIdPkPair(List<String> chargeBoxIdList);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
* @since 19.08.2014
*/
public interface TransactionRepository {
Transaction getTransaction(int transactionPk);

List<Transaction> getTransactions(TransactionQueryForm form);

void writeTransactionsCSV(TransactionQueryForm form, Writer writer);

List<Integer> getActiveTransactionIds(String chargeBoxId);
Integer getActiveTransactionId(String chargeBoxId, Integer connectorId);

TransactionDetails getDetails(int transactionPk);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
*/
package de.rwth.idsg.steve.repository.dto;

import com.fasterxml.jackson.annotation.JsonIgnore;
import de.rwth.idsg.steve.ocpp.OcppProtocol;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -32,17 +34,32 @@
@Getter
@Builder
public final class ConnectorStatus {
private final String chargeBoxId, timeStamp, status, errorCode;
private final int chargeBoxPk, connectorId;
@JsonIgnore
@Schema(description = "Charge Box DB key", hidden = true)
private final int chargeBoxPk;
@Schema(description = "Charge Box ID")
private final String chargeBoxId;
@Schema(description = "Connector ID")
private final int connectorId;

@Schema(description = "Status")
private final String status;
@Schema(description = "Error code")
private final String errorCode;

@Schema(description = "Timestamp")
private final String timeStamp;
// For additional internal processing. Not related to the humanized
// String version above, which is for representation on frontend
@Schema(description = "Timestamp of the status")
private final DateTime statusTimestamp;

@Schema(description = "OCPP version")
private final OcppProtocol ocppProtocol;

// This is true, if the chargeBox this connector belongs to is a WS/JSON station
// and it is disconnected at the moment of building this DTO.
@Schema(description = "Json and Disconnected")
@Setter
@Builder.Default
private boolean jsonAndDisconnected = false;
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/de/rwth/idsg/steve/repository/dto/TaskOverview.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package de.rwth.idsg.steve.repository.dto;

import de.rwth.idsg.steve.ocpp.TaskOrigin;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
Expand All @@ -32,8 +33,17 @@
@EqualsAndHashCode
@Builder
public final class TaskOverview implements Comparable<TaskOverview> {
private final int taskId, responseCount, requestCount;
private final DateTime start, end;
@Schema(description = "Task ID")
private final int taskId;
@Schema(description = "Response count")
private final int responseCount;
@Schema(description = "Request count")
private final int requestCount;
@Schema(description = "Starttime")
private final DateTime start;
@Schema(description = "Endtime")
private final DateTime end;
@Schema(description = "Task triggered internal or external")
private final TaskOrigin origin;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ public List<ChargePointSelect> getChargePointSelect(OcppProtocol protocol, List<
.map(r -> new ChargePointSelect(protocol.getTransport(), r.value1(), r.value2()));
}

@Override // returns List of zero or one ChargeBox
public List<ChargePointSelect> getChargePointSelect(String chageBoxID) {
return ctx.select(CHARGE_BOX.CHARGE_BOX_ID, CHARGE_BOX.ENDPOINT_ADDRESS, CHARGE_BOX.OCPP_PROTOCOL)
.from(CHARGE_BOX)
.where(CHARGE_BOX.CHARGE_BOX_ID.eq(chageBoxID))
.fetch()
.map(r -> new ChargePointSelect(OcppProtocol.fromCompositeValue(r.value3()).getTransport(),
r.value1(), r.value2()));
}

@Override
public List<String> getChargeBoxIds() {
return ctx.select(CHARGE_BOX.CHARGE_BOX_ID)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ public TransactionRepositoryImpl(DSLContext ctx) {
this.ctx = ctx;
}

@Override
public Transaction getTransaction(int transactionPk) {
TransactionQueryForm form = new TransactionQueryForm();
form.setTransactionPk(transactionPk);
form.setReturnCSV(false);
form.setType(TransactionQueryForm.QueryType.ALL);
return getInternal(form).fetchAny(new TransactionMapper());
}

@Override
public List<Transaction> getTransactions(TransactionQueryForm form) {
return getInternal(form).fetch()
Expand All @@ -89,6 +98,19 @@ public List<Integer> getActiveTransactionIds(String chargeBoxId) {
.fetch(TRANSACTION.TRANSACTION_PK);
}

@Override
public Integer getActiveTransactionId(String chargeBoxId, Integer connectorId) {
return ctx.select(TRANSACTION.TRANSACTION_PK)
.from(TRANSACTION)
.join(CONNECTOR)
.on(TRANSACTION.CONNECTOR_PK.equal(CONNECTOR.CONNECTOR_PK))
.and(CONNECTOR.CHARGE_BOX_ID.equal(chargeBoxId))
.where(TRANSACTION.STOP_TIMESTAMP.isNull())
.and(CONNECTOR.CONNECTOR_ID.equal(connectorId))
.orderBy(TRANSACTION.TRANSACTION_PK.desc()) // to avoid fetching ghost transactions, fetch the latest
.fetchAny(TRANSACTION.TRANSACTION_PK);
}

@Override
public TransactionDetails getDetails(int transactionPk) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,33 @@ public int updateFirmware(UpdateFirmwareParams params) {

public int remoteStartTransaction(RemoteStartTransactionParams params) {
RemoteStartTransactionTask task = new RemoteStartTransactionTask(getVersion(), params);
return addRemoteStartTask(task);
}

public int remoteStartTransaction(RemoteStartTransactionParams params, String caller) {
RemoteStartTransactionTask task = new RemoteStartTransactionTask(getVersion(), params, caller);
return addRemoteStartTask(task);
}

private int addRemoteStartTask(RemoteStartTransactionTask task) {
BackgroundService.with(executorService)
.forFirst(task.getParams().getChargePointSelectList())
.execute(c -> getOcpp12Invoker().remoteStartTransaction(c, task));

return taskStore.add(task);
}

public int remoteStopTransaction(RemoteStopTransactionParams params, String caller) {
RemoteStopTransactionTask task = new RemoteStopTransactionTask(getVersion(), params, caller);
return addRemoteStopTask(task);
}

public int remoteStopTransaction(RemoteStopTransactionParams params) {
RemoteStopTransactionTask task = new RemoteStopTransactionTask(getVersion(), params);
return addRemoteStopTask(task);
}

private int addRemoteStopTask(RemoteStopTransactionTask task) {
BackgroundService.with(executorService)
.forFirst(task.getParams().getChargePointSelectList())
.execute(c -> getOcpp12Invoker().remoteStopTransaction(c, task));
Expand All @@ -158,6 +174,15 @@ public int remoteStopTransaction(RemoteStopTransactionParams params) {

public int unlockConnector(UnlockConnectorParams params) {
UnlockConnectorTask task = new UnlockConnectorTask(getVersion(), params);
return addRemoteUnlockTask(task);
}

public int unlockConnector(UnlockConnectorParams params, String caller) {
UnlockConnectorTask task = new UnlockConnectorTask(getVersion(), params, caller);
return addRemoteUnlockTask(task);
}

private int addRemoteUnlockTask(UnlockConnectorTask task) {

BackgroundService.with(executorService)
.forFirst(task.getParams().getChargePointSelectList())
Expand Down
132 changes: 132 additions & 0 deletions src/main/java/de/rwth/idsg/steve/web/api/ConnectorRestController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve
* Copyright (C) 2013-2024 SteVe Community Team
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.rwth.idsg.steve.web.api;

import de.rwth.idsg.steve.repository.ChargePointRepository;
import de.rwth.idsg.steve.repository.dto.ConnectorStatus;
import de.rwth.idsg.steve.service.ChargePointHelperService;
import de.rwth.idsg.steve.utils.ConnectorStatusFilter;
import de.rwth.idsg.steve.web.api.dto.ApiConnectorList;
import de.rwth.idsg.steve.web.dto.ConnectorStatusForm;
import de.rwth.idsg.steve.web.dto.OcppJsonStatus;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;
import static java.util.Objects.isNull;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;


import de.rwth.idsg.steve.web.api.ApiControllerAdvice.ApiErrorResponse;


//import org.springframework.web.bind.annotation.DeleteMapping;

//import org.springframework.web.bind.annotation.PathVariable;
//import org.springframework.web.bind.annotation.PostMapping;
//import org.springframework.web.bind.annotation.PutMapping;


/**
*
* @author fnkbsi
* since 20.10.2023
*
*/
@Slf4j
@RestController
@RequestMapping(value = "/api/v1/connectors", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor
public class ConnectorRestController {

@Autowired private ChargePointRepository chargePointRepository;
@Autowired private ChargePointHelperService chargePointHelperService;

// -------------------------------------------------------------------------
// HTTP methods
// -------------------------------------------------------------------------

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "Bad Request", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ApiErrorResponse.class))}),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ApiErrorResponse.class))}),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ApiErrorResponse.class))})}
)
@GetMapping(value = "")
@ResponseBody
public ApiConnectorList getConnectors(@Valid ConnectorStatusForm queryParams) {
ApiConnectorList conList = new ApiConnectorList();
conList.setChargeBoxList(chargePointRepository.getChargeBoxIds());

conList.setIsFiltered(isFilterd(queryParams));
List<ConnectorStatus> latestList = chargePointHelperService.getChargePointConnectorStatus(queryParams);
List<ConnectorStatus> sortedList;
if (queryParams.getStrategy() == ConnectorStatusForm.Strategy.PreferZero) {
sortedList = ConnectorStatusFilter.filterAndPreferZero(latestList);
} else {
sortedList = ConnectorStatusFilter.filterAndPreferOthersWithStatusOfZero(latestList);
}
conList.setConnectors(sortedList);
return conList;
}

@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "400", description = "Bad Request", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ApiErrorResponse.class))}),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ApiErrorResponse.class))}),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ApiErrorResponse.class))})}
)
@GetMapping(value = "OCPP_JSON_STATUS")
@ResponseBody
public List<OcppJsonStatus> getOcppJsonStatus() {
return chargePointHelperService.getOcppJsonStatus();
}

// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------

private Boolean isFilterd(ConnectorStatusForm queryParams) {
if (!isNull(queryParams)) {
if (!isNull(queryParams.getChargeBoxId())) {
if (!queryParams.getChargeBoxId().isBlank()) {
return true;
}
}
if (!isNull(queryParams.getStatus())) {
if (!queryParams.getStatus().isBlank()) {
return true;
}
}
}
return false;
}
}
Loading
Loading