fix: send preparing connector status before `StartTransaction`
authorJérôme Benoit <jerome.benoit@sap.com>
Wed, 10 Apr 2024 09:08:06 +0000 (11:08 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Wed, 10 Apr 2024 09:08:06 +0000 (11:08 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts

index 926915fb016a5497fd519667dff1199052b666e2..ecd858c9a78e676b2aa0e9990d9359d593144899 100644 (file)
@@ -2221,21 +2221,28 @@ export class ChargingStation extends EventEmitter {
       for (const [evseId, evseStatus] of this.evses) {
         if (evseId > 0) {
           for (const [connectorId, connectorStatus] of evseStatus.connectors) {
-            const connectorBootStatus = getBootConnectorStatus(this, connectorId, connectorStatus)
-            await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus, evseId)
+            await sendAndSetConnectorStatus(
+              this,
+              connectorId,
+              getBootConnectorStatus(this, connectorId, connectorStatus),
+              evseId
+            )
           }
         }
       }
     } else {
       for (const connectorId of this.connectors.keys()) {
         if (connectorId > 0) {
-          const connectorBootStatus = getBootConnectorStatus(
+          await sendAndSetConnectorStatus(
             this,
             connectorId,
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            this.getConnectorStatus(connectorId)!
+            getBootConnectorStatus(
+              this,
+              connectorId,
+              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+              this.getConnectorStatus(connectorId)!
+            )
           )
-          await sendAndSetConnectorStatus(this, connectorId, connectorBootStatus)
         }
       }
     }
index f4a890248c89b40948cc7986e66c9340eae3cc35..6cafcd4bbc7ad0e136123cc2f1a173a2abe09c7a 100644 (file)
@@ -1153,7 +1153,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
   ): Promise<GenericResponse> {
     const { connectorId: transactionConnectorId, idTag, chargingProfile } = commandPayload
     if (!chargingStation.hasConnector(transactionConnectorId)) {
-      return await this.notifyRemoteStartTransactionRejected(
+      return this.notifyRemoteStartTransactionRejected(
         chargingStation,
         transactionConnectorId,
         idTag
@@ -1163,7 +1163,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       !chargingStation.isChargingStationAvailable() ||
       !chargingStation.isConnectorAvailable(transactionConnectorId)
     ) {
-      return await this.notifyRemoteStartTransactionRejected(
+      return this.notifyRemoteStartTransactionRejected(
         chargingStation,
         transactionConnectorId,
         idTag
@@ -1174,17 +1174,12 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
       chargingStation.getAuthorizeRemoteTxRequests() &&
       !(await OCPP16ServiceUtils.isIdTagAuthorized(chargingStation, transactionConnectorId, idTag))
     ) {
-      return await this.notifyRemoteStartTransactionRejected(
+      return this.notifyRemoteStartTransactionRejected(
         chargingStation,
         transactionConnectorId,
         idTag
       )
     }
-    await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-      chargingStation,
-      transactionConnectorId,
-      OCPP16ChargePointStatus.Preparing
-    )
     if (
       chargingProfile != null &&
       !this.setRemoteStartTransactionChargingProfile(
@@ -1193,33 +1188,26 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         chargingProfile
       )
     ) {
-      return await this.notifyRemoteStartTransactionRejected(
+      return this.notifyRemoteStartTransactionRejected(
         chargingStation,
         transactionConnectorId,
         idTag
       )
     }
     logger.debug(
-      `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on connector id ${transactionConnectorId}, idTag '${idTag}'`
+      `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${chargingStation.stationInfo?.chargingStationId}#${transactionConnectorId}}, idTag '${idTag}'`
     )
     return OCPP16Constants.OCPP_RESPONSE_ACCEPTED
   }
 
-  private async notifyRemoteStartTransactionRejected (
+  private notifyRemoteStartTransactionRejected (
     chargingStation: ChargingStation,
     connectorId: number,
     idTag: string
-  ): Promise<GenericResponse> {
+  ): GenericResponse {
     const connectorStatus = chargingStation.getConnectorStatus(connectorId)
-    if (connectorStatus?.status !== OCPP16ChargePointStatus.Available) {
-      await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-        chargingStation,
-        connectorId,
-        OCPP16ChargePointStatus.Available
-      )
-    }
     logger.debug(
-      `${chargingStation.logPrefix()} Remote start transaction REJECTED on connector id ${connectorId}, idTag '${idTag}', availability '${connectorStatus?.availability}', status '${connectorStatus?.status}'`
+      `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId}, idTag '${idTag}', availability '${connectorStatus?.availability}', status '${connectorStatus?.status}'`
     )
     return OCPP16Constants.OCPP_RESPONSE_REJECTED
   }
@@ -1232,7 +1220,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     if (chargingProfile.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.TX_PROFILE) {
       OCPP16ServiceUtils.setChargingProfile(chargingStation, connectorId, chargingProfile)
       logger.debug(
-        `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}: %j`,
+        `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on ${chargingStation.stationInfo?.chargingStationId}#${connectorId}`,
         chargingProfile
       )
       return true
index d673e8a31597cf893691991a50f901b874468677..b9643469a791831937d9774e4ef0b9fb68abacbf 100644 (file)
@@ -167,11 +167,21 @@ export class OCPP16RequestService extends OCPPRequestService {
   public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
     chargingStation: ChargingStation,
     commandName: OCPP16RequestCommand,
-    commandParams?: JsonType,
+    commandParams?: RequestType,
     params?: RequestParams
   ): Promise<ResponseType> {
     // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
     if (OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName)) {
+      // Post request actions hook
+      switch (commandName) {
+        case OCPP16RequestCommand.START_TRANSACTION:
+          await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+            chargingStation,
+            (commandParams as OCPP16StartTransactionRequest).connectorId,
+            OCPP16ChargePointStatus.Preparing
+          )
+          break
+      }
       return (await this.sendMessage(
         chargingStation,
         generateUUID(),
index 24108ba4c1891aba5e220aa32ff45f9299f3c48a..e6c3b43472c8ef0975f3e855deebf51b7c013919 100644 (file)
@@ -816,22 +816,10 @@ export class OCPP16ResponseService extends OCPPResponseService {
     chargingStation: ChargingStation,
     connectorId: number
   ): Promise<void> {
+    chargingStation.stopMeterValues(connectorId)
     const connectorStatus = chargingStation.getConnectorStatus(connectorId)
     resetConnectorStatus(connectorStatus)
-    chargingStation.stopMeterValues(connectorId)
-    if (chargingStation.getReservationBy('connectorId', connectorId) != null) {
-      await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-        chargingStation,
-        connectorId,
-        OCPP16ChargePointStatus.Reserved
-      )
-    } else if (connectorStatus?.status !== OCPP16ChargePointStatus.Available) {
-      await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-        chargingStation,
-        connectorId,
-        OCPP16ChargePointStatus.Available
-      )
-    }
+    await OCPP16ServiceUtils.restoreConnectorStatus(chargingStation, connectorId, connectorStatus)
   }
 
   private async handleResponseStopTransaction (
index 6673b9b43813d8cbf0985bed82001ef085d6b5d1..c9c4b17b24d6060e7ac102e9ab70664f97c2d13a 100644 (file)
@@ -75,11 +75,12 @@ export class OCPP20RequestService extends OCPPRequestService {
   public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
     chargingStation: ChargingStation,
     commandName: OCPP20RequestCommand,
-    commandParams?: JsonType,
+    commandParams?: RequestType,
     params?: RequestParams
   ): Promise<ResponseType> {
     // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
     if (OCPP20ServiceUtils.isRequestCommandSupported(chargingStation, commandName)) {
+      // TODO: post request actions hook
       return (await this.sendMessage(
         chargingStation,
         generateUUID(),
index d7757eaa1af230ddb847e20d1298dbf88267c51f..3ac768c2052c9468fae03c2a30a4cb8fea0e99b8 100644 (file)
@@ -481,8 +481,7 @@ export abstract class OCPPRequestService {
   public abstract requestHandler<ReqType extends JsonType, ResType extends JsonType>(
     chargingStation: ChargingStation,
     commandName: RequestCommand,
-    // FIXME: should be ReqType
-    commandParams?: JsonType,
+    commandParams?: ReqType,
     params?: RequestParams
   ): Promise<ResType>
 }
index 8a42bf67a7b05f361374a1d04bf996ab5d6b304f..02755c4ec3da6b5d90e2bcb97668e2204ea55450 100644 (file)
@@ -18,7 +18,8 @@ import {
   type AuthorizeResponse,
   ChargePointErrorCode,
   ChargingStationEvents,
-  type ConnectorStatusEnum,
+  type ConnectorStatus,
+  ConnectorStatusEnum,
   CurrentType,
   ErrorType,
   FileType,
@@ -194,6 +195,18 @@ export const sendAndSetConnectorStatus = async (
   })
 }
 
+export const restoreConnectorStatus = async (
+  chargingStation: ChargingStation,
+  connectorId: number,
+  connectorStatus: ConnectorStatus | undefined
+): Promise<void> => {
+  if (connectorStatus?.reservation != null) {
+    await sendAndSetConnectorStatus(chargingStation, connectorId, ConnectorStatusEnum.Reserved)
+  } else if (connectorStatus?.status !== ConnectorStatusEnum.Available) {
+    await sendAndSetConnectorStatus(chargingStation, connectorId, ConnectorStatusEnum.Available)
+  }
+}
+
 const checkConnectorStatusTransition = (
   chargingStation: ChargingStation,
   connectorId: number,
@@ -1228,6 +1241,7 @@ const getMeasurandDefaultLocation = (
 export class OCPPServiceUtils {
   public static readonly getMessageTypeString = getMessageTypeString
   public static readonly sendAndSetConnectorStatus = sendAndSetConnectorStatus
+  public static readonly restoreConnectorStatus = restoreConnectorStatus
   public static readonly isIdTagAuthorized = isIdTagAuthorized
   public static readonly buildTransactionEndMeterValue = buildTransactionEndMeterValue
   protected static getSampledValueTemplate = getSampledValueTemplate