Compare commits

...

4 Commits

  1. 2
      src/main/java/com/yablochkov/ocppstub/BootService.java
  2. 43
      src/main/java/com/yablochkov/ocppstub/ConfigService.java
  3. 22
      src/main/java/com/yablochkov/ocppstub/EventHandler.java
  4. 3
      src/main/java/com/yablochkov/ocppstub/SessionService.java
  5. 65
      src/main/java/com/yablochkov/ocppstub/TransactionService.java
  6. 23
      src/main/java/com/yablochkov/ocppstub/rest/ResetController.java

@ -15,7 +15,7 @@ import java.util.UUID;
@RequiredArgsConstructor @RequiredArgsConstructor
public class BootService { public class BootService {
private final static int PASSWD = 1; private final static int PASSWD = 1;
private final static int INTERVAL_SEC = 10; public final static int INTERVAL_SEC = 10;
private final SessionService sessionService; private final SessionService sessionService;
private final TriggerService triggerService; private final TriggerService triggerService;

@ -2,6 +2,7 @@ package com.yablochkov.ocppstub;
import eu.chargetime.ocpp.feature.profile.ServerCoreProfile; import eu.chargetime.ocpp.feature.profile.ServerCoreProfile;
import eu.chargetime.ocpp.model.core.*; import eu.chargetime.ocpp.model.core.*;
import java.util.concurrent.CompletionStage;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -18,32 +19,36 @@ public class ConfigService {
@Lazy @Lazy
@Autowired private ServerCoreProfile coreProfile; @Autowired private ServerCoreProfile coreProfile;
public void sengConfig(UUID sessionIndex) { public boolean sengConfig(UUID sessionIndex) {
log.info("Sending configuration"); log.info("Sending configuration");
ChangeConfigurationRequest configurationRequest = coreProfile ChangeConfigurationRequest configurationRequest = coreProfile
.createChangeConfigurationRequest("AuthorizationKey", DEFAULT_KEY); .createChangeConfigurationRequest("AuthorizationKey", DEFAULT_KEY);
try { try {
server.send(sessionIndex, configurationRequest) var feature = server.send(sessionIndex,
.thenApply(confirmation -> { configurationRequest)
log.debug("Get confirmation"); .thenApply(confirmation -> {
if (confirmation instanceof ChangeConfigurationConfirmation) { log.debug("Get confirmation");
log.debug("Confirmation type is ChangeConfigurationConfirmation"); if (confirmation instanceof ChangeConfigurationConfirmation) {
ConfigurationStatus status = ((ChangeConfigurationConfirmation) confirmation).getStatus(); log.debug("Confirmation type is ChangeConfigurationConfirmation");
if (status == ConfigurationStatus.Accepted) { ConfigurationStatus status = ((ChangeConfigurationConfirmation) confirmation).getStatus();
log.debug("Confirmation status is accepted"); if (status == ConfigurationStatus.Accepted) {
return Void.TYPE; log.debug("Confirmation status is accepted");
} return true;
} }
log.error("Charge point don't confirm password change"); }
throw new RuntimeException("CP don't confirm pass change"); log.error("Charge point don't confirm password change");
}) throw new RuntimeException("CP don't confirm pass change");
.thenRunAsync(() -> { })
log.info("Closing session {}", sessionIndex); .thenApply((state) -> {
server.closeSession(sessionIndex); log.info("Closing session {}", sessionIndex);
}); server.closeSession(sessionIndex);
return state;
});
return feature.toCompletableFuture().get();
} catch (Exception e) { } catch (Exception e) {
log.error("Exception on ChangeConfiguration", e); log.error("Exception on ChangeConfiguration", e);
} }
return false;
} }
} }

@ -1,9 +1,13 @@
package com.yablochkov.ocppstub; package com.yablochkov.ocppstub;
import static com.yablochkov.ocppstub.BootService.INTERVAL_SEC;
import eu.chargetime.ocpp.ServerEvents; import eu.chargetime.ocpp.ServerEvents;
import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler; import eu.chargetime.ocpp.feature.profile.ServerCoreEventHandler;
import eu.chargetime.ocpp.model.SessionInformation; import eu.chargetime.ocpp.model.SessionInformation;
import eu.chargetime.ocpp.model.core.*; import eu.chargetime.ocpp.model.core.*;
import java.time.ZonedDateTime;
import java.util.Optional;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -32,7 +36,11 @@ public class EventHandler implements ServerCoreEventHandler, ServerEvents {
public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) { public BootNotificationConfirmation handleBootNotificationRequest(UUID sessionIndex, BootNotificationRequest request) {
BootNotificationConfirmation response = bootService.handle(sessionIndex, request); BootNotificationConfirmation response = bootService.handle(sessionIndex, request);
if (response.getStatus() == RegistrationStatus.Pending) { if (response.getStatus() == RegistrationStatus.Pending) {
configService.sengConfig(sessionIndex); boolean isConfigSet = configService.sengConfig(sessionIndex);
if (!isConfigSet) {
log.error("Config not set, skip this step");
return new BootNotificationConfirmation(ZonedDateTime.now(), INTERVAL_SEC, RegistrationStatus.Accepted);
}
} }
return response; return response;
} }
@ -68,8 +76,16 @@ public class EventHandler implements ServerCoreEventHandler, ServerEvents {
@Override @Override
public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) { public StopTransactionConfirmation handleStopTransactionRequest(UUID sessionIndex, StopTransactionRequest request) {
log.info("Stop transaction request {}", request); log.info("Stop transaction request {}", request);
transactionService.stopByRequest(sessionIndex, request.getTransactionId()); var transactionId = request.getTransactionId();
return new StopTransactionConfirmation(); transactionService.stopByRequest(sessionIndex, transactionId);
log.info("Prepare stop confirmation");
var confirmation = new StopTransactionConfirmation();
Optional.ofNullable(request.getIdTag())
.ifPresent((idTag) -> confirmation.setIdTagInfo(new IdTagInfo(AuthorizationStatus.Expired)));
log.info("Stop transaction {}, with idTag {} for session {}", transactionId, request.getIdTag(), sessionIndex);
return confirmation;
} }
@Override @Override

@ -54,7 +54,8 @@ public class SessionService {
.filter((entry) -> { .filter((entry) -> {
var entryValue = entry.getValue(); var entryValue = entry.getValue();
if (Objects.nonNull(entryValue)) { if (Objects.nonNull(entryValue)) {
return Objects.equals(entryValue.getIdentifier(), identity); return Objects.equals(entryValue.getIdentifier(), identity) ||
Objects.equals(entryValue.getIdentifier(),"/" + identity);
} }
return false; return false;
}) })

@ -15,8 +15,11 @@ import eu.chargetime.ocpp.model.core.StartTransactionConfirmation;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -26,6 +29,7 @@ import org.springframework.stereotype.Service;
@Service @Service
@Slf4j @Slf4j
public class TransactionService { public class TransactionService {
private final static long REMOTE_TIMEOUT_SEC = 10;
private final AtomicInteger transactionNumber = new AtomicInteger(); private final AtomicInteger transactionNumber = new AtomicInteger();
private final Map<String,Integer> transactionMap = new HashMap<>(); private final Map<String,Integer> transactionMap = new HashMap<>();
@ -55,33 +59,49 @@ public class TransactionService {
var identity = sessionService.getIdentityBySessionId(sessionIndex); var identity = sessionService.getIdentityBySessionId(sessionIndex);
log.info("Try to stop transaction for {}, with id {}", identity, transactionId); log.info("Try to stop transaction for {}, with id {}", identity, transactionId);
if (Objects.nonNull(identity)) { Optional.ofNullable(identity)
transactionMap.remove(identity); .map(transactionMap::remove)
} .filter(Objects::nonNull)
.ifPresentOrElse(
(id) -> log.info("Transaction id {} removed ({} requested)", id, transactionId),
() -> log.info("Nothing to remove for {}", transactionId));
log.info("Stop by request completed");
} }
public RemoteStartTransactionConfirmation remoteStart(String id) { public RemoteStartTransactionConfirmation remoteStart(String identity, Integer connectorId) {
log.info("Try to start transaction for {}", id); log.info("Try to start transaction for {}", identity);
var session = sessionService.getSessionByIdentity(id); var session = sessionService.getSessionByIdentity(identity);
log.info("Found session {}", session); log.info("Found session {}", session);
if (Objects.nonNull(session)) { if (Objects.nonNull(session)) {
try { try {
var future = ocppStub.send(session, //20 char limit
new RemoteStartTransactionRequest(UUID.randomUUID().toString())); String idTag = String.format("%f.0", Math.random() * 1_000_000);
Confirmation confirmation = future.toCompletableFuture().get();
var request = new RemoteStartTransactionRequest(idTag);
if (Objects.nonNull(connectorId)) {
request.setConnectorId(connectorId);
}
log.info("Send start transaction request {}", request);
var future = ocppStub.send(session, request);
Confirmation confirmation = future.toCompletableFuture()
.get(REMOTE_TIMEOUT_SEC, TimeUnit.SECONDS);
if (confirmation instanceof RemoteStartTransactionConfirmation startConfirmation) { if (confirmation instanceof RemoteStartTransactionConfirmation startConfirmation) {
RemoteStartStopStatus status = startConfirmation.getStatus(); var status = startConfirmation.getStatus();
log.info("Start transaction status {}", status); log.info("Start transaction status {}", status);
if (RemoteStartStopStatus.Accepted.equals(status)) { if (RemoteStartStopStatus.Accepted.equals(status)) {
transactionMap.remove(id); transactionMap.remove(identity);
} }
return startConfirmation; return startConfirmation;
} }
} catch (InterruptedException | ExecutionException | OccurenceConstraintException | } catch (InterruptedException | ExecutionException | OccurenceConstraintException |
UnsupportedFeatureException | NotConnectedException e) { UnsupportedFeatureException | NotConnectedException e) {
log.error("Caught exception on transaction start", e); log.error("Caught exception on transaction start", e);
} catch (TimeoutException e) {
log.error("Remote start transaction confirmation exception, ps not responding", e);
} }
} }
throw new RuntimeException("Can't start transaction"); throw new RuntimeException("Can't start transaction");
@ -119,4 +139,27 @@ public class TransactionService {
} }
throw new RuntimeException("Can't stop transaction"); throw new RuntimeException("Can't stop transaction");
} }
public RemoteStopTransactionConfirmation ByIdentityAndTransactionId(String identity, Integer transactionId) {
var session = Optional.ofNullable(sessionService.getSessionByIdentity(identity))
.orElseThrow();
try {
var future = ocppStub.send(session,
new RemoteStopTransactionRequest(transactionId));
var confirmation = future.toCompletableFuture()
.get(REMOTE_TIMEOUT_SEC, TimeUnit.SECONDS);
if (confirmation instanceof RemoteStopTransactionConfirmation stopConsirmation) {
log.info("Stop confirmation: {}", stopConsirmation);
return stopConsirmation;
}
} catch (OccurenceConstraintException | UnsupportedFeatureException | NotConnectedException |
ExecutionException | InterruptedException | TimeoutException e) {
log.error("Can't stop transaction by id", e);
}
throw new RuntimeException();
}
} }

@ -15,8 +15,6 @@ import eu.chargetime.ocpp.model.core.RemoteStopTransactionConfirmation;
import eu.chargetime.ocpp.model.core.ResetConfirmation; import eu.chargetime.ocpp.model.core.ResetConfirmation;
import eu.chargetime.ocpp.model.core.ResetRequest; import eu.chargetime.ocpp.model.core.ResetRequest;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -51,12 +49,7 @@ public class ResetController {
@PathVariable("identity") final String identity, @RequestBody final ResetRequest request) { @PathVariable("identity") final String identity, @RequestBody final ResetRequest request) {
// TODO REFACTOR THIS // TODO REFACTOR THIS
log.info("Send reset to {}, parameters {}", identity, request); log.info("Send reset to {}, parameters {}", identity, request);
var session = sessionService.getCache() var session = sessionService.getSessionByIdentity(identity);
.entrySet().stream()
.filter((entry) -> Objects.equals(entry.getValue().getIdentifier(), identity))
.map(Entry::getKey)
.findFirst()
.orElseThrow();
try { try {
var stage = ocppStub.send(session, request); var stage = ocppStub.send(session, request);
@ -76,11 +69,23 @@ public class ResetController {
@PostMapping("/start/{identity}") @PostMapping("/start/{identity}")
public RemoteStartTransactionConfirmation startTransaction(@PathVariable("identity") final String identity) { public RemoteStartTransactionConfirmation startTransaction(@PathVariable("identity") final String identity) {
return transactionService.remoteStart(identity); return transactionService.remoteStart(identity, null);
}
@PostMapping("/start/{identity}/{connectorId}")
public RemoteStartTransactionConfirmation startTransactionOnConnector(@PathVariable("identity") final String identity, @PathVariable("connectorId") final Integer connectorId) {
return transactionService.remoteStart(identity, connectorId);
} }
@DeleteMapping("/stop/{identity}") @DeleteMapping("/stop/{identity}")
public RemoteStopTransactionConfirmation stopTransaction(@PathVariable("identity") final String identity) { public RemoteStopTransactionConfirmation stopTransaction(@PathVariable("identity") final String identity) {
return transactionService.remoteStop(identity); return transactionService.remoteStop(identity);
} }
@DeleteMapping("/stopById/{identity}/{transactionId}")
public RemoteStopTransactionConfirmation stopTransactionByTransactionId(
@PathVariable("identity") final String identity,
@PathVariable("transactionId") final Integer transactionId ) {
return transactionService.ByIdentityAndTransactionId(identity, transactionId);
}
} }

Loading…
Cancel
Save