From 0005fa7ceb5e8ffed2edf2bb6f64304a33c88fb7 Mon Sep 17 00:00:00 2001 From: Tester Date: Wed, 2 Aug 2023 19:19:31 +0200 Subject: [PATCH 01/30] StringUtils: add method to check mail address --- .../java/de/rwth/idsg/steve/utils/StringUtils.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java b/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java index 7e5cc2413..979ad0884 100644 --- a/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java +++ b/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java @@ -32,6 +32,7 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; +import java.util.regex.Pattern; /** * @author Sevket Goekay @@ -95,4 +96,14 @@ public static String getLastBitFromUrl(final String input) { return input.substring(index + substring.length()); } } + + // https://www.baeldung.com/java-email-validation-regex + public static boolean isValidAddress(String emailAddress) { + String regexPattern = "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"; // Strict Regular Expression Validation + //String regexPattern = "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$"; //Regular Expression for Validation of Non-Latin or Unicode Characters Email + //String regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$" // Regular Expression by RFC 5322 for Email Validation + return Pattern.compile(regexPattern) + .matcher(emailAddress) + .matches(); + } } From 4cbea6f40ec4349818f6d245e8904be54c558e0c Mon Sep 17 00:00:00 2001 From: Tester Date: Wed, 2 Aug 2023 19:21:46 +0200 Subject: [PATCH 02/30] UserRepository: add method "User.Details getDetails(String ocppTag)" --- .../idsg/steve/repository/UserRepository.java | 1 + .../repository/impl/UserRepositoryImpl.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/UserRepository.java b/src/main/java/de/rwth/idsg/steve/repository/UserRepository.java index 840185ecd..63619c5d5 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/UserRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/UserRepository.java @@ -31,6 +31,7 @@ public interface UserRepository { List getOverview(UserQueryForm form); User.Details getDetails(int userPk); + User.Details getDetails(String ocppTag); void add(UserForm form); void update(UserForm form); diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java index b35f69189..cafe551fa 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java @@ -116,6 +116,43 @@ public User.Details getDetails(int userPk) { .build(); } + @Override + public User.Details getDetails(String ocppIdTag) { + + Integer ocppPk = ctx.select(OCPP_TAG.OCPP_TAG_PK) + .from(OCPP_TAG) + .where(OCPP_TAG.ID_TAG.eq(ocppIdTag)) + .fetchOne(OCPP_TAG.OCPP_TAG_PK); + + if (ocppPk == null) { + throw new SteveException("There is no OCPP_Tag: '%s'", ocppIdTag); + } + + // ------------------------------------------------------------------------- + // 1. user table + // ------------------------------------------------------------------------- + + UserRecord ur = ctx.selectFrom(USER) + .where(USER.OCPP_TAG_PK.equal(ocppPk)) + .fetchOne(); + + if (ur == null) { + throw new SteveException("There is no user with OCPP_TAG '%s'", ocppIdTag); + } + + // ------------------------------------------------------------------------- + // 2. address table + // ------------------------------------------------------------------------- + + AddressRecord ar = addressRepository.get(ctx, ur.getAddressPk()); + + return User.Details.builder() + .userRecord(ur) + .address(ar) + .ocppIdTag(Optional.ofNullable(ocppIdTag)) + .build(); + } + @Override public void add(UserForm form) { ctx.transaction(configuration -> { From 75fd4faf8ba2d1ed0c66551e8f9f1d3c640c5aba Mon Sep 17 00:00:00 2001 From: Tester Date: Wed, 2 Aug 2023 19:28:37 +0200 Subject: [PATCH 03/30] TransactionRepository: add method "Transaction getTransaction(int transaction_pk);" --- .../idsg/steve/repository/TransactionRepository.java | 2 ++ .../repository/impl/TransactionRepositoryImpl.java | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java index dec544eee..2efedb959 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java @@ -30,6 +30,8 @@ * @since 19.08.2014 */ public interface TransactionRepository { + Transaction getTransaction(int transaction_pk); + List getTransactions(TransactionQueryForm form); void writeTransactionsCSV(TransactionQueryForm form, Writer writer); diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index 52847e188..77a083133 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -65,6 +65,16 @@ public TransactionRepositoryImpl(DSLContext ctx) { this.ctx = ctx; } + @Override + public Transaction getTransaction(int transaction_pk) { + TransactionQueryForm form = new TransactionQueryForm(); + form.setTransactionPk(transaction_pk); + form.setReturnCSV(false); + form.setType(TransactionQueryForm.QueryType.ALL); + return getInternal(form).fetch() + .map(new TransactionMapper()).get(0); + } + @Override public List getTransactions(TransactionQueryForm form) { return getInternal(form).fetch() From e254786da33346626617902c539f6404965e428a Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Wed, 2 Aug 2023 19:45:48 +0200 Subject: [PATCH 04/30] MailService: change method "send(String subject, String body)" to "send(String subject, String body, String RecipientAddresses)" use addresses from setting if RecipientAddresses is empty; adding method "sendAsync(String subject, String body, String RecipientAddresses)" --- .../rwth/idsg/steve/service/MailService.java | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/MailService.java b/src/main/java/de/rwth/idsg/steve/service/MailService.java index ee338ad0f..6cc9876ce 100644 --- a/src/main/java/de/rwth/idsg/steve/service/MailService.java +++ b/src/main/java/de/rwth/idsg/steve/service/MailService.java @@ -40,6 +40,9 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import static de.rwth.idsg.steve.utils.StringUtils.splitByComma; +import static de.rwth.idsg.steve.utils.StringUtils.isValidAddress; +import java.util.List; /** * @author Sevket Goekay @@ -81,7 +84,7 @@ public MailSettings getSettings() { public void sendTestMail() { try { - send("Test", "Test"); + send("Test", "Test",""); } catch (MessagingException e) { throw new SteveException("Failed to send mail", e); } @@ -90,29 +93,60 @@ public void sendTestMail() { public void sendAsync(String subject, String body) { executorService.execute(() -> { try { - send(subject, body); + send(subject, body, ""); } catch (MessagingException e) { log.error("Failed to send mail", e); } }); } - public void send(String subject, String body) throws MessagingException { - MailSettings settings = getSettings(); + public void sendAsync(String subject, String body, String RecipientAddresses) { + executorService.execute(() -> { + try { + send(subject, body, RecipientAddresses); + } catch (MessagingException e) { + log.error("Failed to send mail", e); + } + }); + } + + private void send(String subject, String body, String RecipientAddresses) throws MessagingException { + MailSettings settingsLocal = getSettings(); - Message mail = new MimeMessage(session); - mail.setSubject("[SteVe] " + subject); - mail.setContent(body, "text/plain"); - mail.setFrom(new InternetAddress(settings.getFrom())); + Message mail = new MimeMessage(session); + mail.setSubject("[SteVe] " + subject); + mail.setContent(body, "text/plain"); + mail.setFrom(new InternetAddress(settingsLocal.getFrom())); - for (String rep : settings.getRecipients()) { + List eMailAddresses; + + if (RecipientAddresses.isEmpty()) + { + eMailAddresses = settingsLocal.getRecipients(); + } + else + { + + eMailAddresses = splitByComma(RecipientAddresses); + } + + for (String rep : eMailAddresses) { + if (isValidAddress(rep)){ mail.addRecipient(Message.RecipientType.TO, new InternetAddress(rep)); } + else{ + log.error("Failed to send mail to " + rep + "! Format of the address is invalid."); + } + } try (Transport transport = session.getTransport()) { transport.connect(); transport.sendMessage(mail, mail.getAllRecipients()); } + catch(Exception e) + { + log.error("Failed to send mail(s)! ", e); + } } // ------------------------------------------------------------------------- From 4eadaa8e8979b12cb2b88884245645895948df18 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Wed, 2 Aug 2023 20:12:34 +0200 Subject: [PATCH 05/30] NotificationService: in method "ocppTransactionEnded(OcppTransactionEnded notification)" adding send mail to user (if email address is in the database), adding createContent method for user mail --- .../steve/service/NotificationService.java | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 269b42b2a..6368b3808 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -41,7 +41,11 @@ import static de.rwth.idsg.steve.NotificationFeature.OcppStationWebSocketDisconnected; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionStarted; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionEnded; +import de.rwth.idsg.steve.repository.TransactionRepository; +import de.rwth.idsg.steve.repository.UserRepository; +import de.rwth.idsg.steve.repository.dto.Transaction; import static java.lang.String.format; +import jooq.steve.db.tables.records.UserRecord; /** * @author Sevket Goekay @@ -52,6 +56,8 @@ public class NotificationService { @Autowired private MailService mailService; + @Autowired private TransactionRepository transactionRepository; + @Autowired private UserRepository userRepository; @EventListener public void ocppStationBooted(OccpStationBooted notification) { @@ -117,7 +123,24 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { @EventListener public void ocppTransactionEnded(OcppTransactionEnded notification) { - if (isDisabled(OcppTransactionEnded)) { + Transaction TransActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); + + TransActParams.getOcppTagPk(); + UserRecord userRecord = userRepository.getDetails(TransActParams.getOcppIdTag()).getUserRecord(); + String eMailAddress = userRecord.getEMail(); + + // mail to user + if (!Strings.isNullOrEmpty(eMailAddress)) { + String subjectUserMail = format("Transaction '%s' has ended on charging station '%s'", TransActParams.getId(), TransActParams.getChargeBoxId()); + + // if the Transactionstop is received within the first 1 Minute don't send an E-Mail + if (TransActParams.getStopTimestamp().isAfter(TransActParams.getStartTimestamp().plusMinutes(1))){ + mailService.sendAsync(subjectUserMail, addTimestamp(createContent(TransActParams, userRecord)), eMailAddress); + } + } + + /* mail defined in settings */ + if (isDisabled(OcppTransactionEnded)) { return; } @@ -156,6 +179,39 @@ private static String createContent(UpdateTransactionParams params) { .toString(); } +private static String createContent(Transaction params, UserRecord userRecord) { + Double meterValueDiff; + Integer meterValueStop; + Integer meterValueStart; + String str_meterValueDiff = "-"; + try + { + meterValueStop = Integer.valueOf(params.getStopValue()); + meterValueStart = Integer.valueOf(params.getStartValue()); + meterValueDiff = (meterValueStop - meterValueStart)/1000.0; // --> kWh + str_meterValueDiff = meterValueDiff.toString() + " kWh"; + } + catch(NumberFormatException e) + { + log.error("Failed to calculate charged energy! ", e); + } + + return new StringBuilder("User: ") + .append(userRecord.getFirstName()).append(" ").append(userRecord.getLastName()) + .append(System.lineSeparator()) + .append(System.lineSeparator()) + .append("Details:").append(System.lineSeparator()) + .append("- chargeBoxId: ").append(params.getChargeBoxId()).append(System.lineSeparator()) + .append("- connectorId: ").append(params.getConnectorId()).append(System.lineSeparator()) + .append("- transactionId: ").append(params.getId()).append(System.lineSeparator()) // getTransactionId() + .append("- startTimestamp (UTC): ").append(params.getStartTimestamp()).append(System.lineSeparator()) + .append("- startMeterValue: ").append(params.getStartValue()).append(System.lineSeparator()) + .append("- stopTimestamp (UTC): ").append(params.getStopTimestamp()).append(System.lineSeparator()) + .append("- stopMeterValue: ").append(params.getStopValue()).append(System.lineSeparator()) + .append("- stopReason: ").append(params.getStopReason()).append(System.lineSeparator()) + .append("- charged energy: ").append(str_meterValueDiff).append(System.lineSeparator()) + .toString(); + } private boolean isDisabled(NotificationFeature f) { MailSettings settings = mailService.getSettings(); From 1b366b4e0e30ac13b03a04b263df63e3bef631c2 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Wed, 2 Aug 2023 21:14:33 +0200 Subject: [PATCH 06/30] OcppStationStatusSuspendedEV.java added --- .../OcppStationStatusSuspendedEV.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java diff --git a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java new file mode 100644 index 000000000..ce6906feb --- /dev/null +++ b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java @@ -0,0 +1,33 @@ +/* + * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve + * Copyright (C) 2013-2023 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 . + */ +package de.rwth.idsg.steve.service.notification; + +import lombok.Data; + +/** + * @author Frank Brosi + * @since 12.10.2022 + * + */ +@Data +public class OcppStationStatusSuspendedEV { + + private final String chargeBoxId; + private final int connectorId; +} From e38a1084512765dcd698ddb00869bf1c3480407c Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Wed, 2 Aug 2023 21:16:12 +0200 Subject: [PATCH 07/30] NotificationFeature.java: added NotificationFeature "OcppStationStatusSuspendedEV" --- src/main/java/de/rwth/idsg/steve/NotificationFeature.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/rwth/idsg/steve/NotificationFeature.java b/src/main/java/de/rwth/idsg/steve/NotificationFeature.java index a5fd343d0..ba43fc6f3 100644 --- a/src/main/java/de/rwth/idsg/steve/NotificationFeature.java +++ b/src/main/java/de/rwth/idsg/steve/NotificationFeature.java @@ -35,6 +35,7 @@ public enum NotificationFeature { OcppStationWebSocketConnected(" a JSON charging station connects"), OcppStationWebSocketDisconnected(" a JSON charging station disconnects"), OcppTransactionStarted(" a charging station starts a transaction"), + OcppStationStatusSuspendedEV(" a EV suspended charging"), OcppTransactionEnded(" a charging station ends a transaction"); From f51a3daea538dc70bd72f425414b61c203c94318 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Wed, 2 Aug 2023 21:20:46 +0200 Subject: [PATCH 08/30] CentralSystemService16_Service.java: on a statusNotification, added publishing a event if the status is "SuspendedEV" --- .../idsg/steve/service/CentralSystemService16_Service.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java b/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java index a55e9ca67..09916db6e 100644 --- a/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java +++ b/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java @@ -27,6 +27,7 @@ import de.rwth.idsg.steve.repository.dto.UpdateTransactionParams; import de.rwth.idsg.steve.service.notification.OccpStationBooted; import de.rwth.idsg.steve.service.notification.OcppStationStatusFailure; +import de.rwth.idsg.steve.service.notification.OcppStationStatusSuspendedEV; import de.rwth.idsg.steve.service.notification.OcppTransactionEnded; import de.rwth.idsg.steve.service.notification.OcppTransactionStarted; import jooq.steve.db.enums.TransactionStopEventActor; @@ -147,6 +148,11 @@ public StatusNotificationResponse statusNotification( chargeBoxIdentity, parameters.getConnectorId(), parameters.getErrorCode().value())); } + if (parameters.getStatus() == ChargePointStatus.SUSPENDED_EV) { + applicationEventPublisher.publishEvent(new OcppStationStatusSuspendedEV( + chargeBoxIdentity, parameters.getConnectorId())); //, connPk)); + } + return new StatusNotificationResponse(); } From df0b5c4fc53dc2d998f6586cb917f2e11be4ce9a Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Wed, 2 Aug 2023 21:22:28 +0200 Subject: [PATCH 09/30] OcppServerRepository: add method getConnectorPK --- .../rwth/idsg/steve/repository/OcppServerRepository.java | 1 + .../steve/repository/impl/OcppServerRepositoryImpl.java | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java b/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java index 4d9d86f46..968bd5e9d 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java @@ -42,6 +42,7 @@ public interface OcppServerRepository { void updateChargeboxHeartbeat(String chargeBoxIdentity, DateTime ts); void insertConnectorStatus(InsertConnectorStatusParams params); + public Integer getConnectorPk(String chargeBoxId, int connectorId); void insertMeterValues(String chargeBoxIdentity, List list, int connectorId, Integer transactionId); void insertMeterValues(String chargeBoxIdentity, List list, int transactionId); diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java index 8ec2542c8..651af9534 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java @@ -165,6 +165,15 @@ public void insertConnectorStatus(InsertConnectorStatusParams p) { }); } + @Override + public Integer getConnectorPk(String chargeBoxId, int connectorId){ + return ctx.select(CONNECTOR.CONNECTOR_PK) + .from(CONNECTOR) + .where(CONNECTOR.CHARGE_BOX_ID.equal(chargeBoxId)) + .and(CONNECTOR.CONNECTOR_ID.equal(connectorId)) + .fetchOne().value1(); + } + @Override public void insertMeterValues(String chargeBoxIdentity, List list, int connectorId, Integer transactionId) { if (CollectionUtils.isEmpty(list)) { From 7f73ecdb4056a859e2418a0295e313d2bbb48237 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Wed, 2 Aug 2023 21:25:43 +0200 Subject: [PATCH 10/30] TransactionRepository: add method getOcppTagOfActiveTransaction(integer connectorPK) --- .../idsg/steve/repository/TransactionRepository.java | 2 ++ .../steve/repository/impl/TransactionRepositoryImpl.java | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java index 2efedb959..70e325968 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java @@ -38,6 +38,8 @@ public interface TransactionRepository { List getActiveTransactionIds(String chargeBoxId); + String getOcppTagOfActiveTransaction(Integer connectorPk); + TransactionDetails getDetails(int transactionPk, boolean firstArrivingMeterValueIfMultiple); default TransactionDetails getDetails(int transactionPk) { diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index 77a083133..a2402168b 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -98,6 +98,15 @@ public List getActiveTransactionIds(String chargeBoxId) { .fetch(TRANSACTION.TRANSACTION_PK); } + @Override + public String getOcppTagOfActiveTransaction(Integer connectorPk) { + return ctx.select(TRANSACTION.ID_TAG) + .from(TRANSACTION) + .where(TRANSACTION.CONNECTOR_PK.eq(connectorPk)) + .and(TRANSACTION.STOP_VALUE.isNull()) + .fetchAny(TRANSACTION.ID_TAG); + } + @Override public TransactionDetails getDetails(int transactionPk, boolean firstArrivingMeterValueIfMultiple) { From 4ca23a6e2814b4131da2280cb0ab640ac2fe2b2b Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Wed, 2 Aug 2023 21:29:36 +0200 Subject: [PATCH 11/30] NotificationService: added Event ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification) to send a mail to the user --- .../steve/service/NotificationService.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 6368b3808..617166f8c 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -41,11 +41,14 @@ import static de.rwth.idsg.steve.NotificationFeature.OcppStationWebSocketDisconnected; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionStarted; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionEnded; +import de.rwth.idsg.steve.repository.OcppServerRepository; import de.rwth.idsg.steve.repository.TransactionRepository; import de.rwth.idsg.steve.repository.UserRepository; import de.rwth.idsg.steve.repository.dto.Transaction; +import de.rwth.idsg.steve.service.notification.OcppStationStatusSuspendedEV; import static java.lang.String.format; import jooq.steve.db.tables.records.UserRecord; +import org.springframework.scheduling.annotation.Async; /** * @author Sevket Goekay @@ -58,6 +61,7 @@ public class NotificationService { @Autowired private MailService mailService; @Autowired private TransactionRepository transactionRepository; @Autowired private UserRepository userRepository; + @Autowired private OcppServerRepository ocppServerRepository; @EventListener public void ocppStationBooted(OccpStationBooted notification) { @@ -122,6 +126,28 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { } @EventListener + @Async + public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification){ + // Connector_pk + Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), notification.getConnectorId()); + String ocppTag = transactionRepository.getOcppTagOfActiveTransaction(connectorPk); + if (ocppTag == null){return;} + UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); + String eMailAddy = userRecord.getEMail(); //userRepository.getMailAddy(OCPP_TAG); + if (Strings.isNullOrEmpty(eMailAddy)) + {return;} + + String subject = format("EV stopped charging at charging station %s", notification.getChargeBoxId()); + + //String body = format("Connector '%s' of charging station '%s' notifies Suspended_EV", connectorId, chargeBoxId); + String body = "User: " + userRecord.getFirstName() + " " + userRecord.getLastName() + System.lineSeparator() + System.lineSeparator() + + "Connector " + notification.getConnectorId() + " of charging station " + notification.getChargeBoxId() + " notifies Suspended_EV"; + + mailService.sendAsync( subject, addTimestamp(body), eMailAddy); + } + + @EventListener + @Async public void ocppTransactionEnded(OcppTransactionEnded notification) { Transaction TransActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); From 64707eeed3eafdd0a7cb54086c857f7610b9a78f Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Fri, 4 Aug 2023 16:20:22 +0200 Subject: [PATCH 12/30] NotificationService & CentralSystemService16_Service: Format and Comment improvements --- .../CentralSystemService16_Service.java | 2 +- .../steve/service/NotificationService.java | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java b/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java index 09916db6e..6b60818a8 100644 --- a/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java +++ b/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java @@ -150,7 +150,7 @@ public StatusNotificationResponse statusNotification( if (parameters.getStatus() == ChargePointStatus.SUSPENDED_EV) { applicationEventPublisher.publishEvent(new OcppStationStatusSuspendedEV( - chargeBoxIdentity, parameters.getConnectorId())); //, connPk)); + chargeBoxIdentity, parameters.getConnectorId())); } return new StatusNotificationResponse(); diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 617166f8c..f802d6109 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -128,18 +128,20 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { @EventListener @Async public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification){ - // Connector_pk Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), notification.getConnectorId()); String ocppTag = transactionRepository.getOcppTagOfActiveTransaction(connectorPk); - if (ocppTag == null){return;} + + if (ocppTag == null){ + return; + } + UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); - String eMailAddy = userRecord.getEMail(); //userRepository.getMailAddy(OCPP_TAG); - if (Strings.isNullOrEmpty(eMailAddy)) - {return;} + String eMailAddy = userRecord.getEMail(); + if (Strings.isNullOrEmpty(eMailAddy)){ + return; + } String subject = format("EV stopped charging at charging station %s", notification.getChargeBoxId()); - - //String body = format("Connector '%s' of charging station '%s' notifies Suspended_EV", connectorId, chargeBoxId); String body = "User: " + userRecord.getFirstName() + " " + userRecord.getLastName() + System.lineSeparator() + System.lineSeparator() + "Connector " + notification.getConnectorId() + " of charging station " + notification.getChargeBoxId() + " notifies Suspended_EV"; @@ -159,7 +161,7 @@ public void ocppTransactionEnded(OcppTransactionEnded notification) { if (!Strings.isNullOrEmpty(eMailAddress)) { String subjectUserMail = format("Transaction '%s' has ended on charging station '%s'", TransActParams.getId(), TransActParams.getChargeBoxId()); - // if the Transactionstop is received within the first 1 Minute don't send an E-Mail + // if the Transactionstop is received within the first Minute don't send an E-Mail if (TransActParams.getStopTimestamp().isAfter(TransActParams.getStartTimestamp().plusMinutes(1))){ mailService.sendAsync(subjectUserMail, addTimestamp(createContent(TransActParams, userRecord)), eMailAddress); } @@ -179,7 +181,6 @@ public void ocppTransactionEnded(OcppTransactionEnded notification) { // Private helpers // ------------------------------------------------------------------------- - private static String createContent(InsertTransactionParams params) { StringBuilder sb = new StringBuilder("Details:").append(System.lineSeparator()) .append("- chargeBoxId: ").append(params.getChargeBoxId()).append(System.lineSeparator()) @@ -229,7 +230,7 @@ private static String createContent(Transaction params, UserRecord userRecord) { .append("Details:").append(System.lineSeparator()) .append("- chargeBoxId: ").append(params.getChargeBoxId()).append(System.lineSeparator()) .append("- connectorId: ").append(params.getConnectorId()).append(System.lineSeparator()) - .append("- transactionId: ").append(params.getId()).append(System.lineSeparator()) // getTransactionId() + .append("- transactionId: ").append(params.getId()).append(System.lineSeparator()) .append("- startTimestamp (UTC): ").append(params.getStartTimestamp()).append(System.lineSeparator()) .append("- startMeterValue: ").append(params.getStartValue()).append(System.lineSeparator()) .append("- stopTimestamp (UTC): ").append(params.getStopTimestamp()).append(System.lineSeparator()) From 00853ffdd7e8903a37eb7c7fcffe187ad1992a75 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Sat, 5 Aug 2023 14:25:31 +0200 Subject: [PATCH 13/30] NotificationService: added mail to "admin" in OcppStationStatusSuspendedEV --- .../de/rwth/idsg/steve/service/NotificationService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index f802d6109..6b289cc2a 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -28,6 +28,7 @@ import de.rwth.idsg.steve.service.notification.OcppStationWebSocketConnected; import de.rwth.idsg.steve.service.notification.OcppStationWebSocketDisconnected; import de.rwth.idsg.steve.service.notification.OcppTransactionEnded; +import de.rwth.idsg.steve.service.notification.OcppStationStatusSuspendedEV; import de.rwth.idsg.steve.service.notification.OcppTransactionStarted; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; @@ -40,12 +41,12 @@ import static de.rwth.idsg.steve.NotificationFeature.OcppStationWebSocketConnected; import static de.rwth.idsg.steve.NotificationFeature.OcppStationWebSocketDisconnected; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionStarted; +import static de.rwth.idsg.steve.NotificationFeature.OcppStationStatusSuspendedEV; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionEnded; import de.rwth.idsg.steve.repository.OcppServerRepository; import de.rwth.idsg.steve.repository.TransactionRepository; import de.rwth.idsg.steve.repository.UserRepository; import de.rwth.idsg.steve.repository.dto.Transaction; -import de.rwth.idsg.steve.service.notification.OcppStationStatusSuspendedEV; import static java.lang.String.format; import jooq.steve.db.tables.records.UserRecord; import org.springframework.scheduling.annotation.Async; @@ -146,6 +147,12 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati + "Connector " + notification.getConnectorId() + " of charging station " + notification.getChargeBoxId() + " notifies Suspended_EV"; mailService.sendAsync( subject, addTimestamp(body), eMailAddy); + + /* mail defined in settings */ + if (isDisabled(OcppStationStatusSuspendedEV)) { + return; + } + mailService.sendAsync( subject, addTimestamp(body), ""); } @EventListener From bf113abd95939915909eadbe2716e3dd3d8fa74a Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Sat, 5 Aug 2023 15:11:58 +0200 Subject: [PATCH 14/30] NotificationService: formated mail text in OcppStationStatusSuspendedEV, rearange the if clauses --- .../steve/service/NotificationService.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 6b289cc2a..118e05923 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -132,26 +132,34 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), notification.getConnectorId()); String ocppTag = transactionRepository.getOcppTagOfActiveTransaction(connectorPk); - if (ocppTag == null){ - return; - } - - UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); - String eMailAddy = userRecord.getEMail(); - if (Strings.isNullOrEmpty(eMailAddy)){ - return; + String subject = format("EV stopped charging at charging station %s, Connector %d", + notification.getChargeBoxId(), + notification.getConnectorId()); + if (ocppTag != null){ + + UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); + String eMailAddy = userRecord.getEMail(); + if (!Strings.isNullOrEmpty(eMailAddy)){ + //String bodyUserMail = "User: " + userRecord.getFirstName() + " " + userRecord.getLastName() + System.lineSeparator() + System.lineSeparator() + // + "Connector " + notification.getConnectorId() + " of charging station " + notification.getChargeBoxId() + " notifies Suspended_EV"; + + String bodyUserMail = format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", + userRecord.getFirstName(), + userRecord.getLastName(), + notification.getConnectorId(), + notification.getChargeBoxId()); + + mailService.sendAsync( subject, addTimestamp(bodyUserMail), eMailAddy); + } } - String subject = format("EV stopped charging at charging station %s", notification.getChargeBoxId()); - String body = "User: " + userRecord.getFirstName() + " " + userRecord.getLastName() + System.lineSeparator() + System.lineSeparator() - + "Connector " + notification.getConnectorId() + " of charging station " + notification.getChargeBoxId() + " notifies Suspended_EV"; - - mailService.sendAsync( subject, addTimestamp(body), eMailAddy); - /* mail defined in settings */ if (isDisabled(OcppStationStatusSuspendedEV)) { return; } + String body = format("Connector %d of charging station %s notifies Suspended_EV", + notification.getConnectorId(), + notification.getChargeBoxId()); mailService.sendAsync( subject, addTimestamp(body), ""); } From 43922964455b49de38e6cef32b508c1d26b7885d Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Thu, 12 Oct 2023 12:28:44 +0200 Subject: [PATCH 15/30] NotificationService.java & OcppStationStatusSuspend: commeting and format changes --- .../steve/service/NotificationService.java | 34 +++++++++++++------ .../OcppStationStatusSuspendedEV.java | 2 +- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 118e05923..ba646608e 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -109,7 +109,10 @@ public void ocppStationStatusFailure(OcppStationStatusFailure notification) { return; } - String subject = format("Connector '%s' of charging station '%s' is FAULTED", notification.getConnectorId(), notification.getChargeBoxId()); + String subject = format("Connector '%s' of charging station '%s' is FAULTED", + notification.getConnectorId(), + notification.getChargeBoxId() + ); String body = format("Status Error Code: '%s'", notification.getErrorCode()); mailService.sendAsync(subject, addTimestamp(body)); @@ -121,7 +124,11 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { return; } - String subject = format("Transaction '%s' has started on charging station '%s' on connector '%s'", notification.getTransactionId(), notification.getParams().getChargeBoxId(), notification.getParams().getConnectorId()); + String subject = format("Transaction '%s' has started on charging station '%s' on connector '%s'", + notification.getTransactionId(), + notification.getParams().getChargeBoxId(), + notification.getParams().getConnectorId() + ); mailService.sendAsync(subject, addTimestamp(createContent(notification.getParams()))); } @@ -139,15 +146,14 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); String eMailAddy = userRecord.getEMail(); + // send email if user with eMail address found if (!Strings.isNullOrEmpty(eMailAddy)){ - //String bodyUserMail = "User: " + userRecord.getFirstName() + " " + userRecord.getLastName() + System.lineSeparator() + System.lineSeparator() - // + "Connector " + notification.getConnectorId() + " of charging station " + notification.getChargeBoxId() + " notifies Suspended_EV"; - String bodyUserMail = format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", - userRecord.getFirstName(), - userRecord.getLastName(), - notification.getConnectorId(), - notification.getChargeBoxId()); + userRecord.getFirstName(), + userRecord.getLastName(), + notification.getConnectorId(), + notification.getChargeBoxId() + ); mailService.sendAsync( subject, addTimestamp(bodyUserMail), eMailAddy); } @@ -174,7 +180,10 @@ public void ocppTransactionEnded(OcppTransactionEnded notification) { // mail to user if (!Strings.isNullOrEmpty(eMailAddress)) { - String subjectUserMail = format("Transaction '%s' has ended on charging station '%s'", TransActParams.getId(), TransActParams.getChargeBoxId()); + String subjectUserMail = format("Transaction '%s' has ended on charging station '%s'", + TransActParams.getId(), + TransActParams.getChargeBoxId() + ); // if the Transactionstop is received within the first Minute don't send an E-Mail if (TransActParams.getStopTimestamp().isAfter(TransActParams.getStartTimestamp().plusMinutes(1))){ @@ -187,7 +196,10 @@ public void ocppTransactionEnded(OcppTransactionEnded notification) { return; } - String subject = format("Transaction '%s' has ended on charging station '%s'", notification.getParams().getTransactionId(), notification.getParams().getChargeBoxId()); + String subject = format("Transaction '%s' has ended on charging station '%s'", + notification.getParams().getTransactionId(), + notification.getParams().getChargeBoxId() + ); mailService.sendAsync(subject, addTimestamp(createContent(notification.getParams()))); } diff --git a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java index ce6906feb..8a984a004 100644 --- a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java +++ b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java @@ -21,7 +21,7 @@ import lombok.Data; /** - * @author Frank Brosi + * @author fnkbsi * @since 12.10.2022 * */ From 8e44e3891f12ae3ce7c5941aab3ec00e3e4c8850 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Thu, 12 Oct 2023 13:54:17 +0200 Subject: [PATCH 16/30] style correction --- .../repository/OcppServerRepository.java | 2 +- .../repository/TransactionRepository.java | 2 +- .../impl/OcppServerRepositoryImpl.java | 4 +- .../impl/TransactionRepositoryImpl.java | 4 +- .../repository/impl/UserRepositoryImpl.java | 3 +- .../steve/service/NotificationService.java | 76 ++++++++++--------- .../OcppStationStatusSuspendedEV.java | 2 +- .../de/rwth/idsg/steve/utils/StringUtils.java | 11 ++- 8 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java b/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java index 968bd5e9d..e0f2e451c 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java @@ -42,7 +42,7 @@ public interface OcppServerRepository { void updateChargeboxHeartbeat(String chargeBoxIdentity, DateTime ts); void insertConnectorStatus(InsertConnectorStatusParams params); - public Integer getConnectorPk(String chargeBoxId, int connectorId); + Integer getConnectorPk(String chargeBoxId, int connectorId); void insertMeterValues(String chargeBoxIdentity, List list, int connectorId, Integer transactionId); void insertMeterValues(String chargeBoxIdentity, List list, int transactionId); diff --git a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java index 70e325968..9375e46b5 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java @@ -30,7 +30,7 @@ * @since 19.08.2014 */ public interface TransactionRepository { - Transaction getTransaction(int transaction_pk); + Transaction getTransaction(int transactionPk); List getTransactions(TransactionQueryForm form); diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java index 651af9534..3042475e9 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java @@ -166,12 +166,12 @@ public void insertConnectorStatus(InsertConnectorStatusParams p) { } @Override - public Integer getConnectorPk(String chargeBoxId, int connectorId){ + public Integer getConnectorPk(String chargeBoxId, int connectorId) { return ctx.select(CONNECTOR.CONNECTOR_PK) .from(CONNECTOR) .where(CONNECTOR.CHARGE_BOX_ID.equal(chargeBoxId)) .and(CONNECTOR.CONNECTOR_ID.equal(connectorId)) - .fetchOne().value1(); + .fetchOne().value1(); } @Override diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index a2402168b..badf6d71d 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -66,9 +66,9 @@ public TransactionRepositoryImpl(DSLContext ctx) { } @Override - public Transaction getTransaction(int transaction_pk) { + public Transaction getTransaction(int transactionPk) { TransactionQueryForm form = new TransactionQueryForm(); - form.setTransactionPk(transaction_pk); + form.setTransactionPk(transactionPk); form.setReturnCSV(false); form.setType(TransactionQueryForm.QueryType.ALL); return getInternal(form).fetch() diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java index cafe551fa..dd255b707 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/UserRepositoryImpl.java @@ -118,12 +118,11 @@ public User.Details getDetails(int userPk) { @Override public User.Details getDetails(String ocppIdTag) { - Integer ocppPk = ctx.select(OCPP_TAG.OCPP_TAG_PK) .from(OCPP_TAG) .where(OCPP_TAG.ID_TAG.eq(ocppIdTag)) .fetchOne(OCPP_TAG.OCPP_TAG_PK); - + if (ocppPk == null) { throw new SteveException("There is no OCPP_Tag: '%s'", ocppIdTag); } diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index ba646608e..0cd4fb4b5 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -109,7 +109,7 @@ public void ocppStationStatusFailure(OcppStationStatusFailure notification) { return; } - String subject = format("Connector '%s' of charging station '%s' is FAULTED", + String subject = format("Connector '%s' of charging station '%s' is FAULTED", notification.getConnectorId(), notification.getChargeBoxId() ); @@ -135,27 +135,31 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { @EventListener @Async - public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification){ - Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), notification.getConnectorId()); + public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification) { + Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), + notification.getConnectorId() + ); String ocppTag = transactionRepository.getOcppTagOfActiveTransaction(connectorPk); - String subject = format("EV stopped charging at charging station %s, Connector %d", - notification.getChargeBoxId(), - notification.getConnectorId()); + String subject = format("EV stopped charging at charging station %s, Connector %d", + notification.getChargeBoxId(), + notification.getConnectorId() + ); if (ocppTag != null){ UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); String eMailAddy = userRecord.getEMail(); // send email if user with eMail address found - if (!Strings.isNullOrEmpty(eMailAddy)){ - String bodyUserMail = format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", - userRecord.getFirstName(), - userRecord.getLastName(), - notification.getConnectorId(), - notification.getChargeBoxId() - ); - - mailService.sendAsync( subject, addTimestamp(bodyUserMail), eMailAddy); + if (!Strings.isNullOrEmpty(eMailAddy)) { + String bodyUserMail = + format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", + userRecord.getFirstName(), + userRecord.getLastName(), + notification.getConnectorId(), + notification.getChargeBoxId() + ); + + mailService.sendAsync(subject, addTimestamp(bodyUserMail), eMailAddy); } } @@ -163,31 +167,35 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati if (isDisabled(OcppStationStatusSuspendedEV)) { return; } - String body = format("Connector %d of charging station %s notifies Suspended_EV", + String body = format("Connector %d of charging station %s notifies Suspended_EV", notification.getConnectorId(), - notification.getChargeBoxId()); - mailService.sendAsync( subject, addTimestamp(body), ""); + notification.getChargeBoxId() + ); + mailService.sendAsync(subject, addTimestamp(body), ""); } @EventListener @Async public void ocppTransactionEnded(OcppTransactionEnded notification) { - Transaction TransActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); + Transaction transActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); - TransActParams.getOcppTagPk(); - UserRecord userRecord = userRepository.getDetails(TransActParams.getOcppIdTag()).getUserRecord(); + transActParams.getOcppTagPk(); + UserRecord userRecord = userRepository.getDetails(transActParams.getOcppIdTag()).getUserRecord(); String eMailAddress = userRecord.getEMail(); // mail to user if (!Strings.isNullOrEmpty(eMailAddress)) { - String subjectUserMail = format("Transaction '%s' has ended on charging station '%s'", - TransActParams.getId(), - TransActParams.getChargeBoxId() + String subjectUserMail = format("Transaction '%s' has ended on charging station '%s'", + transActParams.getId(), + transActParams.getChargeBoxId() ); // if the Transactionstop is received within the first Minute don't send an E-Mail - if (TransActParams.getStopTimestamp().isAfter(TransActParams.getStartTimestamp().plusMinutes(1))){ - mailService.sendAsync(subjectUserMail, addTimestamp(createContent(TransActParams, userRecord)), eMailAddress); + if (transActParams.getStopTimestamp().isAfter(transActParams.getStartTimestamp().plusMinutes(1))) { + mailService.sendAsync(subjectUserMail, + addTimestamp(createContent(transActParams, userRecord)), + eMailAddress + ); } } @@ -233,20 +241,18 @@ private static String createContent(UpdateTransactionParams params) { .toString(); } -private static String createContent(Transaction params, UserRecord userRecord) { + private static String createContent(Transaction params, UserRecord userRecord) { Double meterValueDiff; Integer meterValueStop; Integer meterValueStart; - String str_meterValueDiff = "-"; - try - { + String strMeterValueDiff = "-"; + try { meterValueStop = Integer.valueOf(params.getStopValue()); meterValueStart = Integer.valueOf(params.getStartValue()); - meterValueDiff = (meterValueStop - meterValueStart)/1000.0; // --> kWh - str_meterValueDiff = meterValueDiff.toString() + " kWh"; + meterValueDiff = (meterValueStop - meterValueStart) / 1000.0; // --> kWh + strMeterValueDiff = meterValueDiff.toString() + " kWh"; } - catch(NumberFormatException e) - { + catch(NumberFormatException e) { log.error("Failed to calculate charged energy! ", e); } @@ -263,7 +269,7 @@ private static String createContent(Transaction params, UserRecord userRecord) { .append("- stopTimestamp (UTC): ").append(params.getStopTimestamp()).append(System.lineSeparator()) .append("- stopMeterValue: ").append(params.getStopValue()).append(System.lineSeparator()) .append("- stopReason: ").append(params.getStopReason()).append(System.lineSeparator()) - .append("- charged energy: ").append(str_meterValueDiff).append(System.lineSeparator()) + .append("- charged energy: ").append(strMeterValueDiff).append(System.lineSeparator()) .toString(); } diff --git a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java index 8a984a004..487380206 100644 --- a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java +++ b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java @@ -23,8 +23,8 @@ /** * @author fnkbsi * @since 12.10.2022 - * */ + @Data public class OcppStationStatusSuspendedEV { diff --git a/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java b/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java index 979ad0884..fe3d38496 100644 --- a/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java +++ b/src/main/java/de/rwth/idsg/steve/utils/StringUtils.java @@ -99,9 +99,14 @@ public static String getLastBitFromUrl(final String input) { // https://www.baeldung.com/java-email-validation-regex public static boolean isValidAddress(String emailAddress) { - String regexPattern = "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"; // Strict Regular Expression Validation - //String regexPattern = "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$"; //Regular Expression for Validation of Non-Latin or Unicode Characters Email - //String regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$" // Regular Expression by RFC 5322 for Email Validation + // Strict Regular Expression Validation + String regexPattern = + "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"; + //Regular Expression for Validation of Non-Latin or Unicode Characters Email + //String regexPattern = + // "^(?=.{1,64}@)[\\p{L}0-9_-]+(\\.[\\p{L}0-9_-]+)*@[^-][\\p{L}0-9-]+(\\.[\\p{L}0-9-]+)*(\\.[\\p{L}]{2,})$"; + // Regular Expression by RFC 5322 for Email Validation + //String regexPattern = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$" return Pattern.compile(regexPattern) .matcher(emailAddress) .matches(); From 472b75dea6ae921bd718157103e6db09e2208d3e Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Tue, 17 Oct 2023 13:58:04 +0200 Subject: [PATCH 17/30] style correction --- .../rwth/idsg/steve/service/MailService.java | 50 ++++++++----------- .../steve/service/NotificationService.java | 16 +++--- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/MailService.java b/src/main/java/de/rwth/idsg/steve/service/MailService.java index 6cc9876ce..864dc0f1a 100644 --- a/src/main/java/de/rwth/idsg/steve/service/MailService.java +++ b/src/main/java/de/rwth/idsg/steve/service/MailService.java @@ -84,7 +84,7 @@ public MailSettings getSettings() { public void sendTestMail() { try { - send("Test", "Test",""); + send("Test", "Test", ""); } catch (MessagingException e) { throw new SteveException("Failed to send mail", e); } @@ -100,51 +100,45 @@ public void sendAsync(String subject, String body) { }); } - public void sendAsync(String subject, String body, String RecipientAddresses) { + public void sendAsync(String subject, String body, String recipientAddresses) { executorService.execute(() -> { try { - send(subject, body, RecipientAddresses); + send(subject, body, recipientAddresses); } catch (MessagingException e) { log.error("Failed to send mail", e); } }); } - private void send(String subject, String body, String RecipientAddresses) throws MessagingException { - MailSettings settingsLocal = getSettings(); + private void send(String subject, String body, String recipientAddresses) throws MessagingException { + MailSettings settingsLocal = getSettings(); - Message mail = new MimeMessage(session); - mail.setSubject("[SteVe] " + subject); - mail.setContent(body, "text/plain"); - mail.setFrom(new InternetAddress(settingsLocal.getFrom())); + Message mail = new MimeMessage(session); + mail.setSubject("[SteVe] " + subject); + mail.setContent(body, "text/plain"); + mail.setFrom(new InternetAddress(settingsLocal.getFrom())); - List eMailAddresses; + List eMailAddresses; - if (RecipientAddresses.isEmpty()) - { - eMailAddresses = settingsLocal.getRecipients(); - } - else - { - - eMailAddresses = splitByComma(RecipientAddresses); - } - - for (String rep : eMailAddresses) { - if (isValidAddress(rep)){ - mail.addRecipient(Message.RecipientType.TO, new InternetAddress(rep)); + if (recipientAddresses.isEmpty()) { + eMailAddresses = settingsLocal.getRecipients(); + } else { + eMailAddresses = splitByComma(recipientAddresses); } - else{ - log.error("Failed to send mail to " + rep + "! Format of the address is invalid."); + + for (String rep : eMailAddresses) { + if (isValidAddress(rep)) { + mail.addRecipient(Message.RecipientType.TO, new InternetAddress(rep)); + } else { + log.error("Failed to send mail to " + rep + "! Format of the address is invalid."); + } } - } try (Transport transport = session.getTransport()) { transport.connect(); transport.sendMessage(mail, mail.getAllRecipients()); } - catch(Exception e) - { + catch (Exception e) { log.error("Failed to send mail(s)! ", e); } } diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 0cd4fb4b5..faba8a2d5 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -136,7 +136,7 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { @EventListener @Async public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification) { - Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), + Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), notification.getConnectorId() ); String ocppTag = transactionRepository.getOcppTagOfActiveTransaction(connectorPk); @@ -145,13 +145,12 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati notification.getChargeBoxId(), notification.getConnectorId() ); - if (ocppTag != null){ - + if (ocppTag != null) { UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); String eMailAddy = userRecord.getEMail(); // send email if user with eMail address found if (!Strings.isNullOrEmpty(eMailAddy)) { - String bodyUserMail = + String bodyUserMail = format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", userRecord.getFirstName(), userRecord.getLastName(), @@ -163,7 +162,7 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati } } - /* mail defined in settings */ + /* mail defined in settings */ if (isDisabled(OcppStationStatusSuspendedEV)) { return; } @@ -199,7 +198,7 @@ public void ocppTransactionEnded(OcppTransactionEnded notification) { } } - /* mail defined in settings */ + /* mail defined in settings */ if (isDisabled(OcppTransactionEnded)) { return; } @@ -251,11 +250,10 @@ private static String createContent(Transaction params, UserRecord userRecord) { meterValueStart = Integer.valueOf(params.getStartValue()); meterValueDiff = (meterValueStop - meterValueStart) / 1000.0; // --> kWh strMeterValueDiff = meterValueDiff.toString() + " kWh"; - } - catch(NumberFormatException e) { + } catch (NumberFormatException e) { log.error("Failed to calculate charged energy! ", e); } - + return new StringBuilder("User: ") .append(userRecord.getFirstName()).append(" ").append(userRecord.getLastName()) .append(System.lineSeparator()) From 953abb4937af129aab2ddea9cfc6581baf87bcc6 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Sat, 23 Dec 2023 21:33:59 +0100 Subject: [PATCH 18/30] TransactionRepositoryImpl, method getOcppTagOfActiveTransaction: order by transactionPk desc, to avoid fetching ghost transactions --- .../idsg/steve/repository/impl/TransactionRepositoryImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index badf6d71d..4d344b99f 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -104,6 +104,7 @@ public String getOcppTagOfActiveTransaction(Integer connectorPk) { .from(TRANSACTION) .where(TRANSACTION.CONNECTOR_PK.eq(connectorPk)) .and(TRANSACTION.STOP_VALUE.isNull()) + .orderBy(TRANSACTION.TRANSACTION_PK.desc()) // to avoid fetching ghost transactions, fetch the latest .fetchAny(TRANSACTION.ID_TAG); } From 48d7a68a929a1ccca8cf7a2649f9688ad43cb423 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Sat, 23 Dec 2023 21:38:41 +0100 Subject: [PATCH 19/30] NotificationService, SuspendedEV & TransactionStop: catch exception in case of no user is found by the OcppTag --- .../steve/service/NotificationService.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index faba8a2d5..6466242a5 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -146,10 +146,16 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati notification.getConnectorId() ); if (ocppTag != null) { - UserRecord userRecord = userRepository.getDetails(ocppTag).getUserRecord(); - String eMailAddy = userRecord.getEMail(); + String eMailAddress = null; + UserRecord userRecord = new UserRecord(); + try { + userRecord = userRepository.getDetails(ocppTag).getUserRecord(); + eMailAddress = userRecord.getEMail(); + } catch (Exception e) { + log.error("Failed to send email (SuspendedEV). User not found! ", e); + } // send email if user with eMail address found - if (!Strings.isNullOrEmpty(eMailAddy)) { + if (!Strings.isNullOrEmpty(eMailAddress)) { String bodyUserMail = format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", userRecord.getFirstName(), @@ -158,7 +164,7 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati notification.getChargeBoxId() ); - mailService.sendAsync(subject, addTimestamp(bodyUserMail), eMailAddy); + mailService.sendAsync(subject, addTimestamp(bodyUserMail), eMailAddress); } } @@ -170,17 +176,24 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati notification.getConnectorId(), notification.getChargeBoxId() ); - mailService.sendAsync(subject, addTimestamp(body), ""); + mailService.sendAsync(subject, addTimestamp(body)); } @EventListener @Async public void ocppTransactionEnded(OcppTransactionEnded notification) { + String eMailAddress = null; + UserRecord userRecord = new UserRecord(); + Transaction transActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); transActParams.getOcppTagPk(); - UserRecord userRecord = userRepository.getDetails(transActParams.getOcppIdTag()).getUserRecord(); - String eMailAddress = userRecord.getEMail(); + try { + userRecord = userRepository.getDetails(transActParams.getOcppIdTag()).getUserRecord(); + eMailAddress = userRecord.getEMail(); + } catch (Exception e) { + log.error("Failed to send email (TransactionStop). User not found! ", e); + } // mail to user if (!Strings.isNullOrEmpty(eMailAddress)) { From 6a2a70234ed6ed148666ff2cb18c2b554c19ae44 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Mon, 25 Dec 2023 18:44:04 +0100 Subject: [PATCH 20/30] Removed unnecessary code --- .../java/de/rwth/idsg/steve/service/NotificationService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 6466242a5..bb9b82401 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -187,7 +187,6 @@ public void ocppTransactionEnded(OcppTransactionEnded notification) { Transaction transActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); - transActParams.getOcppTagPk(); try { userRecord = userRepository.getDetails(transActParams.getOcppIdTag()).getUserRecord(); eMailAddress = userRecord.getEMail(); From eb64190779ba198307ac48d031d0688ee8d7caf8 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Mon, 25 Dec 2023 22:34:43 +0100 Subject: [PATCH 21/30] NotificationService: shorten the error log message (no stack info) --- .../de/rwth/idsg/steve/service/NotificationService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index bb9b82401..0f9289e7b 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -152,7 +152,7 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati userRecord = userRepository.getDetails(ocppTag).getUserRecord(); eMailAddress = userRecord.getEMail(); } catch (Exception e) { - log.error("Failed to send email (SuspendedEV). User not found! ", e); + log.error("Failed to send email (SuspendedEV). User not found! " + e.getMessage()); } // send email if user with eMail address found if (!Strings.isNullOrEmpty(eMailAddress)) { @@ -184,14 +184,14 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati public void ocppTransactionEnded(OcppTransactionEnded notification) { String eMailAddress = null; UserRecord userRecord = new UserRecord(); - + Transaction transActParams = transactionRepository.getTransaction(notification.getParams().getTransactionId()); try { userRecord = userRepository.getDetails(transActParams.getOcppIdTag()).getUserRecord(); eMailAddress = userRecord.getEMail(); } catch (Exception e) { - log.error("Failed to send email (TransactionStop). User not found! ", e); + log.error("Failed to send email (TransactionStop). User not found! " + e.getMessage()); } // mail to user From 102ea169d594c5d168d5d727529ce4ad23a44065 Mon Sep 17 00:00:00 2001 From: fnkbsi <> Date: Mon, 25 Dec 2023 22:41:42 +0100 Subject: [PATCH 22/30] BeanConfiguration: add @EnableAsync to activate @Async in NotificationService --- src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java b/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java index 234c2caad..dc50ff9cc 100644 --- a/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java +++ b/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java @@ -48,6 +48,7 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -79,6 +80,7 @@ @Configuration @EnableWebMvc @EnableScheduling +@EnableAsync @ComponentScan("de.rwth.idsg.steve") public class BeanConfiguration implements WebMvcConfigurer { From 1798ba913fa4ca2b6fd3ee6922f5d629be688116 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 26 Dec 2023 01:18:41 +0100 Subject: [PATCH 23/30] BeanConfiguration: removed @EnableAsync because it's notcompiling under Java 17 --- src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java b/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java index dc50ff9cc..234c2caad 100644 --- a/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java +++ b/src/main/java/de/rwth/idsg/steve/config/BeanConfiguration.java @@ -48,7 +48,6 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -80,7 +79,6 @@ @Configuration @EnableWebMvc @EnableScheduling -@EnableAsync @ComponentScan("de.rwth.idsg.steve") public class BeanConfiguration implements WebMvcConfigurer { From 14ac662c7d939264029a4349c3714020b4322c50 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 26 Dec 2023 01:23:17 +0100 Subject: [PATCH 24/30] NotificationService: removing @Async annotations. Realizing async instead with ScheduledExecutorService, so response to the chargepoint is not blocked. --- .../steve/service/NotificationService.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 0f9289e7b..0b44d4b70 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -49,7 +49,7 @@ import de.rwth.idsg.steve.repository.dto.Transaction; import static java.lang.String.format; import jooq.steve.db.tables.records.UserRecord; -import org.springframework.scheduling.annotation.Async; +import java.util.concurrent.ScheduledExecutorService; /** * @author Sevket Goekay @@ -63,6 +63,7 @@ public class NotificationService { @Autowired private TransactionRepository transactionRepository; @Autowired private UserRepository userRepository; @Autowired private OcppServerRepository ocppServerRepository; + @Autowired private ScheduledExecutorService executorService; @EventListener public void ocppStationBooted(OccpStationBooted notification) { @@ -134,8 +135,17 @@ public void ocppTransactionStarted(OcppTransactionStarted notification) { } @EventListener - @Async public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notification) { + executorService.execute(() -> { + try { + notificationActionSuspendedEV(notification); + } catch (Exception e) { + log.error("Failed to execute the notification of SuspendedEV", e); + } + }); + } + + private void notificationActionSuspendedEV(OcppStationStatusSuspendedEV notification) { Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), notification.getConnectorId() ); @@ -180,8 +190,17 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati } @EventListener - @Async public void ocppTransactionEnded(OcppTransactionEnded notification) { + executorService.execute(() -> { + try { + notificationActionTransactionEnded(notification); + } catch (Exception e) { + log.error("Failed to execute the notification of SuspendedEV", e); + } + }); + } + + private void notificationActionTransactionEnded(OcppTransactionEnded notification) { String eMailAddress = null; UserRecord userRecord = new UserRecord(); From 6a9091c2aea761de470b8bb85b151af4fbbe3dd0 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 23 Jan 2024 12:45:52 +0100 Subject: [PATCH 25/30] OcppServerRepository remove method getConnectorPk --- .../idsg/steve/repository/OcppServerRepository.java | 3 +-- .../repository/impl/OcppServerRepositoryImpl.java | 11 +---------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java b/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java index e0f2e451c..7bb7ece35 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/OcppServerRepository.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -42,7 +42,6 @@ public interface OcppServerRepository { void updateChargeboxHeartbeat(String chargeBoxIdentity, DateTime ts); void insertConnectorStatus(InsertConnectorStatusParams params); - Integer getConnectorPk(String chargeBoxId, int connectorId); void insertMeterValues(String chargeBoxIdentity, List list, int connectorId, Integer transactionId); void insertMeterValues(String chargeBoxIdentity, List list, int transactionId); diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java index c290261e8..14530fad1 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/OcppServerRepositoryImpl.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -165,15 +165,6 @@ public void insertConnectorStatus(InsertConnectorStatusParams p) { }); } - @Override - public Integer getConnectorPk(String chargeBoxId, int connectorId) { - return ctx.select(CONNECTOR.CONNECTOR_PK) - .from(CONNECTOR) - .where(CONNECTOR.CHARGE_BOX_ID.equal(chargeBoxId)) - .and(CONNECTOR.CONNECTOR_ID.equal(connectorId)) - .fetchOne().value1(); - } - @Override public void insertMeterValues(String chargeBoxIdentity, List list, int connectorId, Integer transactionId) { if (CollectionUtils.isEmpty(list)) { From 3d26aa225e2413d75f7973c443dcc17f934dcafd Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 23 Jan 2024 12:54:22 +0100 Subject: [PATCH 26/30] TransactionRepository: add method getActiveTransactionId(String chagerBox, Integer connectorId); remove method getOcppTagOfActiveTransaction (Integer connectorPk) --- .../repository/TransactionRepository.java | 5 ++--- .../impl/TransactionRepositoryImpl.java | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java index 9375e46b5..835ce8665 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java +++ b/src/main/java/de/rwth/idsg/steve/repository/TransactionRepository.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -37,8 +37,7 @@ public interface TransactionRepository { void writeTransactionsCSV(TransactionQueryForm form, Writer writer); List getActiveTransactionIds(String chargeBoxId); - - String getOcppTagOfActiveTransaction(Integer connectorPk); + Integer getActiveTransactionId(String chargeBoxId, Integer connectorId); TransactionDetails getDetails(int transactionPk, boolean firstArrivingMeterValueIfMultiple); diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index 4d344b99f..70ec7a739 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -99,13 +99,15 @@ public List getActiveTransactionIds(String chargeBoxId) { } @Override - public String getOcppTagOfActiveTransaction(Integer connectorPk) { - return ctx.select(TRANSACTION.ID_TAG) - .from(TRANSACTION) - .where(TRANSACTION.CONNECTOR_PK.eq(connectorPk)) - .and(TRANSACTION.STOP_VALUE.isNull()) - .orderBy(TRANSACTION.TRANSACTION_PK.desc()) // to avoid fetching ghost transactions, fetch the latest - .fetchAny(TRANSACTION.ID_TAG); + 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)) + .fetchAny(TRANSACTION.TRANSACTION_PK); } @Override From 4c66f000db23e700a8c9b94f0b630f4e6c76f8c1 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 23 Jan 2024 12:56:59 +0100 Subject: [PATCH 27/30] add timestamp to SUSPENDED_EV notification --- .../idsg/steve/service/CentralSystemService16_Service.java | 4 ++-- .../service/notification/OcppStationStatusSuspendedEV.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java b/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java index 6b60818a8..e337a9883 100644 --- a/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java +++ b/src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -150,7 +150,7 @@ public StatusNotificationResponse statusNotification( if (parameters.getStatus() == ChargePointStatus.SUSPENDED_EV) { applicationEventPublisher.publishEvent(new OcppStationStatusSuspendedEV( - chargeBoxIdentity, parameters.getConnectorId())); + chargeBoxIdentity, parameters.getConnectorId(), parameters.getTimestamp())); } return new StatusNotificationResponse(); diff --git a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java index 487380206..fed6cbdd0 100644 --- a/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java +++ b/src/main/java/de/rwth/idsg/steve/service/notification/OcppStationStatusSuspendedEV.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -19,6 +19,7 @@ package de.rwth.idsg.steve.service.notification; import lombok.Data; +import org.joda.time.DateTime; /** * @author fnkbsi @@ -30,4 +31,5 @@ public class OcppStationStatusSuspendedEV { private final String chargeBoxId; private final int connectorId; + private final DateTime timestamp; } From 4d2963abfc8c3820fb0e4aeede241b4106033c75 Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 23 Jan 2024 13:08:39 +0100 Subject: [PATCH 28/30] adapt methode notificationActionSuspendedEV -> removed ocppServerRepository and suppress sending a mail in the first minute --- .../steve/service/NotificationService.java | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java index 0b44d4b70..f2a6d5560 100644 --- a/src/main/java/de/rwth/idsg/steve/service/NotificationService.java +++ b/src/main/java/de/rwth/idsg/steve/service/NotificationService.java @@ -1,6 +1,6 @@ /* * SteVe - SteckdosenVerwaltung - https://github.com/steve-community/steve - * Copyright (C) 2013-2023 SteVe Community Team + * Copyright (C) 2013-2024 SteVe Community Team * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify @@ -43,7 +43,6 @@ import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionStarted; import static de.rwth.idsg.steve.NotificationFeature.OcppStationStatusSuspendedEV; import static de.rwth.idsg.steve.NotificationFeature.OcppTransactionEnded; -import de.rwth.idsg.steve.repository.OcppServerRepository; import de.rwth.idsg.steve.repository.TransactionRepository; import de.rwth.idsg.steve.repository.UserRepository; import de.rwth.idsg.steve.repository.dto.Transaction; @@ -62,7 +61,6 @@ public class NotificationService { @Autowired private MailService mailService; @Autowired private TransactionRepository transactionRepository; @Autowired private UserRepository userRepository; - @Autowired private OcppServerRepository ocppServerRepository; @Autowired private ScheduledExecutorService executorService; @EventListener @@ -146,35 +144,39 @@ public void ocppStationStatusSuspendedEV(OcppStationStatusSuspendedEV notificati } private void notificationActionSuspendedEV(OcppStationStatusSuspendedEV notification) { - Integer connectorPk = ocppServerRepository.getConnectorPk(notification.getChargeBoxId(), - notification.getConnectorId() - ); - String ocppTag = transactionRepository.getOcppTagOfActiveTransaction(connectorPk); - String subject = format("EV stopped charging at charging station %s, Connector %d", notification.getChargeBoxId(), notification.getConnectorId() ); - if (ocppTag != null) { - String eMailAddress = null; - UserRecord userRecord = new UserRecord(); - try { - userRecord = userRepository.getDetails(ocppTag).getUserRecord(); - eMailAddress = userRecord.getEMail(); - } catch (Exception e) { - log.error("Failed to send email (SuspendedEV). User not found! " + e.getMessage()); - } - // send email if user with eMail address found - if (!Strings.isNullOrEmpty(eMailAddress)) { - String bodyUserMail = - format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", - userRecord.getFirstName(), - userRecord.getLastName(), - notification.getConnectorId(), - notification.getChargeBoxId() - ); - - mailService.sendAsync(subject, addTimestamp(bodyUserMail), eMailAddress); + + Integer transactionPk = transactionRepository.getActiveTransactionId(notification.getChargeBoxId(), + notification.getConnectorId()); + if (transactionPk != null) { + Transaction transaction = transactionRepository.getTransaction(transactionPk); + String ocppTag = transaction.getOcppIdTag(); + if (ocppTag != null) { + // No mail directly after the start of the transaction, + if (notification.getTimestamp().isAfter(transaction.getStartTimestamp().plusMinutes(1))) { + String eMailAddress = null; + UserRecord userRecord = new UserRecord(); + try { + userRecord = userRepository.getDetails(ocppTag).getUserRecord(); + eMailAddress = userRecord.getEMail(); + } catch (Exception e) { + log.error("Failed to send email (SuspendedEV). User not found! " + e.getMessage()); + } + // send email if user with eMail address found + if (!Strings.isNullOrEmpty(eMailAddress)) { + String bodyUserMail = + format("User: %s %s \n\n Connector %d of charging station %s notifies Suspended_EV", + userRecord.getFirstName(), + userRecord.getLastName(), + notification.getConnectorId(), + notification.getChargeBoxId() + ); + mailService.sendAsync(subject, addTimestamp(bodyUserMail), eMailAddress); + } + } } } From 230c1ee8816b08c2be01bd1498c0437075806c7a Mon Sep 17 00:00:00 2001 From: fnkbsi Date: Tue, 23 Jan 2024 13:21:34 +0100 Subject: [PATCH 29/30] getActiveTransactionId(String chargeBox, Integer connectorId) method, add .orderBy(TRANSACTION.TRANSACTION_PK.desc()) to avoid fetching ghost transactions, fetch the latest --- .../idsg/steve/repository/impl/TransactionRepositoryImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index 70ec7a739..339421071 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -107,6 +107,7 @@ public Integer getActiveTransactionId(String chargeBoxId, Integer connectorId) { .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); } From 9faa7b4d112ae27064c59cbd4b396b159c3f9e02 Mon Sep 17 00:00:00 2001 From: fnkbsi <135032168+fnkbsi@users.noreply.github.com> Date: Wed, 3 Apr 2024 14:46:40 +0200 Subject: [PATCH 30/30] Restore @override annotation after reslove conflict --- .../idsg/steve/repository/impl/TransactionRepositoryImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java index 9417e7d7e..4f7697d36 100644 --- a/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java +++ b/src/main/java/de/rwth/idsg/steve/repository/impl/TransactionRepositoryImpl.java @@ -110,6 +110,7 @@ public Integer getActiveTransactionId(String chargeBoxId, Integer connectorId) { .fetchAny(TRANSACTION.TRANSACTION_PK); } + @Override public TransactionDetails getDetails(int transactionPk) { // -------------------------------------------------------------------------