feat: add support for evses in all identified code paths
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 28 Apr 2023 19:13:24 +0000 (21:13 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 28 Apr 2023 19:13:24 +0000 (21:13 +0200)
Reference: https://github.com/SAP/e-mobility-charging-stations-simulator/issues/349

Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationUtils.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts

index b52fb585a63c226b5998ea444158d0496c24a0c2..e9e8c88102f220610f00f430bed72ec8dd3c1f6c 100644 (file)
@@ -366,6 +366,26 @@ export class ChargingStation {
     }
   }
 
+  public getNumberOfRunningTransactions(): number {
+    let trxCount = 0;
+    if (this.hasEvses) {
+      for (const evseStatus of this.evses.values()) {
+        for (const connectorStatus of evseStatus.connectors.values()) {
+          if (connectorStatus.transactionStarted === true) {
+            ++trxCount;
+          }
+        }
+      }
+    } else {
+      for (const connectorId of this.connectors.keys()) {
+        if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
+          ++trxCount;
+        }
+      }
+    }
+    return trxCount;
+  }
+
   public getOutOfOrderEndMeterValues(): boolean {
     return this.stationInfo?.outOfOrderEndMeterValues ?? false;
   }
@@ -1025,9 +1045,9 @@ export class ChargingStation {
   }
 
   private handleUnsupportedVersion(version: OCPPVersion) {
-    const errMsg = `Unsupported protocol version '${version}' configured in template file ${this.templateFile}`;
-    logger.error(`${this.logPrefix()} ${errMsg}`);
-    throw new BaseError(errMsg);
+    const errorMsg = `Unsupported protocol version '${version}' configured in template file ${this.templateFile}`;
+    logger.error(`${this.logPrefix()} ${errorMsg}`);
+    throw new BaseError(errorMsg);
   }
 
   private initialize(): void {
@@ -1291,9 +1311,9 @@ export class ChargingStation {
 
   private initializeConnectors(stationInfo: ChargingStationInfo): void {
     if (!stationInfo?.Connectors && this.connectors.size === 0) {
-      const logMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no connectors configuration defined`;
-      logger.error(`${this.logPrefix()} ${logMsg}`);
-      throw new BaseError(logMsg);
+      const errorMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no connectors configuration defined`;
+      logger.error(`${this.logPrefix()} ${errorMsg}`);
+      throw new BaseError(errorMsg);
     }
     if (!stationInfo?.Connectors[0]) {
       logger.warn(
@@ -1384,9 +1404,9 @@ export class ChargingStation {
 
   private initializeEvses(stationInfo: ChargingStationInfo): void {
     if (!stationInfo?.Evses && this.evses.size === 0) {
-      const logMsg = `No already defined evses and charging station information from template ${this.templateFile} with no evses configuration defined`;
-      logger.error(`${this.logPrefix()} ${logMsg}`);
-      throw new BaseError(logMsg);
+      const errorMsg = `No already defined evses and charging station information from template ${this.templateFile} with no evses configuration defined`;
+      logger.error(`${this.logPrefix()} ${errorMsg}`);
+      throw new BaseError(errorMsg);
     }
     if (!stationInfo?.Evses[0]) {
       logger.warn(
@@ -1751,7 +1771,7 @@ export class ChargingStation {
   private async onMessage(data: RawData): Promise<void> {
     let request: IncomingRequest | Response | ErrorResponse;
     let messageType: number;
-    let errMsg: string;
+    let errorMsg: string;
     try {
       request = JSON.parse(data.toString()) as IncomingRequest | Response | ErrorResponse;
       if (Array.isArray(request) === true) {
@@ -1773,9 +1793,9 @@ export class ChargingStation {
           // Unknown Message
           default:
             // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
-            errMsg = `Wrong message type ${messageType}`;
-            logger.error(`${this.logPrefix()} ${errMsg}`);
-            throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg);
+            errorMsg = `Wrong message type ${messageType}`;
+            logger.error(`${this.logPrefix()} ${errorMsg}`);
+            throw new OCPPError(ErrorType.PROTOCOL_ERROR, errorMsg);
         }
         parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
       } else {
@@ -1860,26 +1880,6 @@ export class ChargingStation {
     return localStationInfo?.useConnectorId0 ?? true;
   }
 
-  private getNumberOfRunningTransactions(): number {
-    let trxCount = 0;
-    if (this.hasEvses) {
-      for (const evseStatus of this.evses.values()) {
-        for (const connectorStatus of evseStatus.connectors.values()) {
-          if (connectorStatus.transactionStarted === true) {
-            trxCount++;
-          }
-        }
-      }
-    } else {
-      for (const connectorId of this.connectors.keys()) {
-        if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted === true) {
-          trxCount++;
-        }
-      }
-    }
-    return trxCount;
-  }
-
   private async stopRunningTransactions(reason = StopTransactionReason.NONE): Promise<void> {
     if (this.hasEvses) {
       for (const evseStatus of this.evses.values()) {
index f967ddd40ebc3df51d4597b917d6b5ed9cb8a470..c58db0ceec198b570bd90dd8e6a8e91b3c3fbc6e 100644 (file)
@@ -532,7 +532,7 @@ export class ChargingStationUtils {
     templateFile: string,
     logPrefix: string
   ): Voltage {
-    const errMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
+    const errorMsg = `Unknown ${currentType} currentOutType in template file ${templateFile}, cannot define default voltage out`;
     let defaultVoltageOut: number;
     switch (currentType) {
       case CurrentType.AC:
@@ -542,8 +542,8 @@ export class ChargingStationUtils {
         defaultVoltageOut = Voltage.VOLTAGE_400;
         break;
       default:
-        logger.error(`${logPrefix} ${errMsg}`);
-        throw new BaseError(errMsg);
+        logger.error(`${logPrefix} ${errorMsg}`);
+        throw new BaseError(errorMsg);
     }
     return defaultVoltageOut;
   }
index f715adc3cc563214158832835f3213b1f3b55f6e..2ed3202b887d3482dc1b1ab6c3d77e3cf442edfa 100644 (file)
@@ -746,11 +746,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     if (connectorId === 0) {
       let response: ChangeAvailabilityResponse =
         OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
-      for (const id of chargingStation.connectors.keys()) {
-        if (chargingStation.getConnectorStatus(id)?.transactionStarted === true) {
+      const changeAvailability = async (id: number, connectorStatus: ConnectorStatus) => {
+        if (connectorStatus?.transactionStarted === true) {
           response = OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
         }
-        chargingStation.getConnectorStatus(id).availability = commandPayload.type;
+        connectorStatus.availability = commandPayload.type;
         if (response === OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
           await OCPP16ServiceUtils.sendAndSetConnectorStatus(
             chargingStation,
@@ -758,6 +758,17 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
             chargePointStatus
           );
         }
+      };
+      if (chargingStation.hasEvses) {
+        for (const evseStatus of chargingStation.evses.values()) {
+          for (const [id, connectorStatus] of evseStatus.connectors) {
+            await changeAvailability(id, connectorStatus);
+          }
+        }
+      } else {
+        for (const id of chargingStation.connectors.keys()) {
+          await changeAvailability(id, chargingStation.getConnectorStatus(id));
+        }
       }
       return response;
     } else if (
@@ -973,24 +984,39 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     commandPayload: RemoteStopTransactionRequest
   ): Promise<GenericResponse> {
     const transactionId = commandPayload.transactionId;
-    for (const connectorId of chargingStation.connectors.keys()) {
-      if (
-        connectorId > 0 &&
-        chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
-      ) {
-        await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-          chargingStation,
-          connectorId,
-          OCPP16ChargePointStatus.Finishing
-        );
-        const stopResponse = await chargingStation.stopTransactionOnConnector(
-          connectorId,
-          OCPP16StopTransactionReason.REMOTE
-        );
-        if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
-          return OCPP16Constants.OCPP_RESPONSE_ACCEPTED;
+    const remoteStopTransaction = async (connectorId: number): Promise<GenericResponse> => {
+      await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+        chargingStation,
+        connectorId,
+        OCPP16ChargePointStatus.Finishing
+      );
+      const stopResponse = await chargingStation.stopTransactionOnConnector(
+        connectorId,
+        OCPP16StopTransactionReason.REMOTE
+      );
+      if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
+        return OCPP16Constants.OCPP_RESPONSE_ACCEPTED;
+      }
+      return OCPP16Constants.OCPP_RESPONSE_REJECTED;
+    };
+    if (chargingStation.hasEvses) {
+      for (const [evseId, evseStatus] of chargingStation.evses) {
+        if (evseId > 0) {
+          for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+            if (connectorStatus.transactionId === transactionId) {
+              return remoteStopTransaction(connectorId);
+            }
+          }
+        }
+      }
+    } else {
+      for (const connectorId of chargingStation.connectors.keys()) {
+        if (
+          connectorId > 0 &&
+          chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
+        ) {
+          return remoteStopTransaction(connectorId);
         }
-        return OCPP16Constants.OCPP_RESPONSE_REJECTED;
       }
     }
     logger.warn(
@@ -1054,16 +1080,32 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     ) {
       return;
     }
-    for (const connectorId of chargingStation.connectors.keys()) {
-      if (
-        connectorId > 0 &&
-        chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false
-      ) {
-        await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-          chargingStation,
-          connectorId,
-          OCPP16ChargePointStatus.Unavailable
-        );
+    if (chargingStation.hasEvses) {
+      for (const [evseId, evseStatus] of chargingStation.evses) {
+        if (evseId > 0) {
+          for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+            if (connectorStatus?.transactionStarted === false) {
+              await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+                chargingStation,
+                connectorId,
+                OCPP16ChargePointStatus.Unavailable
+              );
+            }
+          }
+        }
+      }
+    } else {
+      for (const connectorId of chargingStation.connectors.keys()) {
+        if (
+          connectorId > 0 &&
+          chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false
+        ) {
+          await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+            chargingStation,
+            connectorId,
+            OCPP16ChargePointStatus.Unavailable
+          );
+        }
       }
     }
     await chargingStation.ocppRequestService.requestHandler<
@@ -1099,19 +1141,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     let wasTransactionsStarted = false;
     let transactionsStarted: boolean;
     do {
-      let trxCount = 0;
-      for (const connectorId of chargingStation.connectors.keys()) {
-        if (
-          connectorId > 0 &&
-          chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true
-        ) {
-          trxCount++;
-        }
-      }
-      if (trxCount > 0) {
+      const runningTransactions = chargingStation.getNumberOfRunningTransactions();
+      if (runningTransactions > 0) {
         const waitTime = 15 * 1000;
         logger.debug(
-          `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${trxCount} transaction(s) in progress, waiting ${
+          `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${runningTransactions} transaction(s) in progress, waiting ${
             waitTime / 1000
           } seconds before continuing firmware update simulation`
         );
@@ -1119,17 +1153,33 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         transactionsStarted = true;
         wasTransactionsStarted = true;
       } else {
-        for (const connectorId of chargingStation.connectors.keys()) {
-          if (
-            connectorId > 0 &&
-            chargingStation.getConnectorStatus(connectorId)?.status !==
-              OCPP16ChargePointStatus.Unavailable
-          ) {
-            await OCPP16ServiceUtils.sendAndSetConnectorStatus(
-              chargingStation,
-              connectorId,
-              OCPP16ChargePointStatus.Unavailable
-            );
+        if (chargingStation.hasEvses) {
+          for (const [evseId, evseStatus] of chargingStation.evses) {
+            if (evseId > 0) {
+              for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+                if (connectorStatus?.status !== OCPP16ChargePointStatus.Unavailable) {
+                  await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+                    chargingStation,
+                    connectorId,
+                    OCPP16ChargePointStatus.Unavailable
+                  );
+                }
+              }
+            }
+          }
+        } else {
+          for (const connectorId of chargingStation.connectors.keys()) {
+            if (
+              connectorId > 0 &&
+              chargingStation.getConnectorStatus(connectorId)?.status !==
+                OCPP16ChargePointStatus.Unavailable
+            ) {
+              await OCPP16ServiceUtils.sendAndSetConnectorStatus(
+                chargingStation,
+                connectorId,
+                OCPP16ChargePointStatus.Unavailable
+              );
+            }
           }
         }
         transactionsStarted = false;
@@ -1370,24 +1420,49 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                 )
                 .catch(Constants.EMPTY_FUNCTION);
             } else {
-              for (const connectorId of chargingStation.connectors.keys()) {
-                chargingStation.ocppRequestService
-                  .requestHandler<
-                    OCPP16StatusNotificationRequest,
-                    OCPP16StatusNotificationResponse
-                  >(
-                    chargingStation,
-                    OCPP16RequestCommand.STATUS_NOTIFICATION,
-                    {
-                      connectorId,
-                      errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
-                      status: chargingStation.getConnectorStatus(connectorId)?.status,
-                    },
-                    {
-                      triggerMessage: true,
-                    }
-                  )
-                  .catch(Constants.EMPTY_FUNCTION);
+              // eslint-disable-next-line no-lonely-if
+              if (chargingStation.hasEvses) {
+                for (const evseStatus of chargingStation.evses.values()) {
+                  for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+                    chargingStation.ocppRequestService
+                      .requestHandler<
+                        OCPP16StatusNotificationRequest,
+                        OCPP16StatusNotificationResponse
+                      >(
+                        chargingStation,
+                        OCPP16RequestCommand.STATUS_NOTIFICATION,
+                        {
+                          connectorId,
+                          errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                          status: connectorStatus.status,
+                        },
+                        {
+                          triggerMessage: true,
+                        }
+                      )
+                      .catch(Constants.EMPTY_FUNCTION);
+                  }
+                }
+              } else {
+                for (const connectorId of chargingStation.connectors.keys()) {
+                  chargingStation.ocppRequestService
+                    .requestHandler<
+                      OCPP16StatusNotificationRequest,
+                      OCPP16StatusNotificationResponse
+                    >(
+                      chargingStation,
+                      OCPP16RequestCommand.STATUS_NOTIFICATION,
+                      {
+                        connectorId,
+                        errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                        status: chargingStation.getConnectorStatus(connectorId)?.status,
+                      },
+                      {
+                        triggerMessage: true,
+                      }
+                    )
+                    .catch(Constants.EMPTY_FUNCTION);
+                }
               }
             }
           }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY);
index 5cc6cbe7312ad701699bb1beb1087352e4191126..54a25b0bf6b41d691e6f36c3be3c975c48b529f1 100644 (file)
@@ -403,13 +403,26 @@ export class OCPP16ResponseService extends OCPPResponseService {
     requestPayload: OCPP16AuthorizeRequest
   ): void {
     let authorizeConnectorId: number;
-    for (const connectorId of chargingStation.connectors.keys()) {
-      if (
-        connectorId > 0 &&
-        chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag
-      ) {
-        authorizeConnectorId = connectorId;
-        break;
+    if (chargingStation.hasEvses) {
+      for (const [evseId, evseStatus] of chargingStation.evses) {
+        if (evseId > 0) {
+          for (const [connectorId, connectorStatus] of evseStatus.connectors) {
+            if (connectorStatus?.authorizeIdTag === requestPayload.idTag) {
+              authorizeConnectorId = connectorId;
+              break;
+            }
+          }
+        }
+      }
+    } else {
+      for (const connectorId of chargingStation.connectors.keys()) {
+        if (
+          connectorId > 0 &&
+          chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag
+        ) {
+          authorizeConnectorId = connectorId;
+          break;
+        }
       }
     }
     const authorizeConnectorIdDefined = !Utils.isNullOrUndefined(authorizeConnectorId);