refactor: cleanup nullish values handling
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 12 Jan 2024 16:45:03 +0000 (17:45 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 12 Jan 2024 16:45:03 +0000 (17:45 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/Helpers.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.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/OCPPServiceUtils.ts

index 1f2b1d7815154f172ccde1e35a93e3a172365c09..47ffecf2b1ebd2be207eaf7dc0a92b000448c754 100644 (file)
@@ -427,8 +427,10 @@ export class ChargingStation extends EventEmitter {
     return numberOfRunningTransactions
   }
 
-  public getConnectorIdByTransactionId (transactionId: number): number | undefined {
-    if (this.hasEvses) {
+  public getConnectorIdByTransactionId (transactionId: number | undefined): number | undefined {
+    if (transactionId == null) {
+      return undefined
+    } else if (this.hasEvses) {
       for (const evseStatus of this.evses.values()) {
         for (const [connectorId, connectorStatus] of evseStatus.connectors) {
           if (connectorStatus.transactionId === transactionId) {
@@ -446,19 +448,18 @@ export class ChargingStation extends EventEmitter {
   }
 
   public getEnergyActiveImportRegisterByTransactionId (
-    transactionId: number,
+    transactionId: number | undefined,
     rounded = false
   ): number {
     return this.getEnergyActiveImportRegister(
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.getConnectorStatus(this.getConnectorIdByTransactionId(transactionId)!)!,
+      this.getConnectorStatus(this.getConnectorIdByTransactionId(transactionId)!),
       rounded
     )
   }
 
   public getEnergyActiveImportRegisterByConnectorId (connectorId: number, rounded = false): number {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    return this.getEnergyActiveImportRegister(this.getConnectorStatus(connectorId)!, rounded)
+    return this.getEnergyActiveImportRegister(this.getConnectorStatus(connectorId), rounded)
   }
 
   public getAuthorizeRemoteTxRequests (): boolean {
@@ -561,21 +562,22 @@ export class ChargingStation extends EventEmitter {
       logger.error(`${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId}`)
       return
     }
-    if (this.getConnectorStatus(connectorId) == null) {
+    const connectorStatus = this.getConnectorStatus(connectorId)
+    if (connectorStatus == null) {
       logger.error(
         `${this.logPrefix()} Trying to start MeterValues on non existing connector id
           ${connectorId}`
       )
       return
     }
-    if (this.getConnectorStatus(connectorId)?.transactionStarted === false) {
+    if (connectorStatus.transactionStarted === false) {
       logger.error(
         `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId} with no transaction started`
       )
       return
     } else if (
-      this.getConnectorStatus(connectorId)?.transactionStarted === true &&
-      this.getConnectorStatus(connectorId)?.transactionId == null
+      connectorStatus.transactionStarted === true &&
+      connectorStatus.transactionId == null
     ) {
       logger.error(
         `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId} with no transaction id`
@@ -583,13 +585,12 @@ export class ChargingStation extends EventEmitter {
       return
     }
     if (interval > 0) {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.getConnectorStatus(connectorId)!.transactionSetInterval = setInterval(() => {
+      connectorStatus.transactionSetInterval = setInterval(() => {
         const meterValue = buildMeterValue(
           this,
           connectorId,
           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          this.getConnectorStatus(connectorId)!.transactionId!,
+          connectorStatus.transactionId!,
           interval
         )
         this.ocppRequestService
@@ -598,7 +599,7 @@ export class ChargingStation extends EventEmitter {
           RequestCommand.METER_VALUES,
           {
             connectorId,
-            transactionId: this.getConnectorStatus(connectorId)?.transactionId,
+            transactionId: connectorStatus.transactionId,
             meterValue: [meterValue]
           }
         )
@@ -619,8 +620,9 @@ export class ChargingStation extends EventEmitter {
   }
 
   public stopMeterValues (connectorId: number): void {
-    if (this.getConnectorStatus(connectorId)?.transactionSetInterval != null) {
-      clearInterval(this.getConnectorStatus(connectorId)?.transactionSetInterval)
+    const connectorStatus = this.getConnectorStatus(connectorId)
+    if (connectorStatus?.transactionSetInterval != null) {
+      clearInterval(connectorStatus.transactionSetInterval)
     }
   }
 
@@ -859,8 +861,7 @@ export class ChargingStation extends EventEmitter {
     connectorId: number,
     reason?: StopTransactionReason
   ): Promise<StopTransactionResponse> {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const transactionId = this.getConnectorStatus(connectorId)!.transactionId!
+    const transactionId = this.getConnectorStatus(connectorId)?.transactionId
     if (
       this.stationInfo?.beginEndMeterValues === true &&
       this.stationInfo.ocppStrictCompliance === true &&
@@ -2018,20 +2019,25 @@ export class ChargingStation extends EventEmitter {
     logger.error(`${this.logPrefix()} WebSocket error:`, error)
   }
 
-  private getEnergyActiveImportRegister (connectorStatus: ConnectorStatus, rounded = false): number {
+  private getEnergyActiveImportRegister (
+    connectorStatus: ConnectorStatus | undefined,
+    rounded = false
+  ): number {
     if (this.stationInfo?.meteringPerTransaction === true) {
       return (
         (rounded
-          ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          Math.round(connectorStatus.transactionEnergyActiveImportRegisterValue!)
-          : connectorStatus.transactionEnergyActiveImportRegisterValue) ?? 0
+          ? connectorStatus?.transactionEnergyActiveImportRegisterValue != null
+            ? Math.round(connectorStatus.transactionEnergyActiveImportRegisterValue)
+            : undefined
+          : connectorStatus?.transactionEnergyActiveImportRegisterValue) ?? 0
       )
     }
     return (
       (rounded
-        ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        Math.round(connectorStatus.energyActiveImportRegisterValue!)
-        : connectorStatus.energyActiveImportRegisterValue) ?? 0
+        ? connectorStatus?.energyActiveImportRegisterValue != null
+          ? Math.round(connectorStatus.energyActiveImportRegisterValue)
+          : undefined
+        : connectorStatus?.energyActiveImportRegisterValue) ?? 0
     )
   }
 
index d8ef4a328e1c5a4fdef6d09acf1da05294f9cfc8..bb736f3f8157cd553b719afc7583af699d7a1436 100644 (file)
@@ -367,7 +367,10 @@ export const initializeConnectorsMapStatus = (
   }
 }
 
-export const resetConnectorStatus = (connectorStatus: ConnectorStatus): void => {
+export const resetConnectorStatus = (connectorStatus: ConnectorStatus | undefined): void => {
+  if (connectorStatus == null) {
+    return
+  }
   connectorStatus.chargingProfiles =
     connectorStatus.transactionId != null && isNotEmptyArray(connectorStatus.chargingProfiles)
       ? connectorStatus.chargingProfiles?.filter(
@@ -795,8 +798,7 @@ const getLimitFromChargingProfiles = (
 ): ChargingProfilesLimit | undefined => {
   const debugLogMsg = `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Matching charging profile found for power limitation: %j`
   const currentDate = new Date()
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-  const connectorStatus = chargingStation.getConnectorStatus(connectorId)!
+  const connectorStatus = chargingStation.getConnectorStatus(connectorId)
   for (const chargingProfile of chargingProfiles) {
     const chargingSchedule = chargingProfile.chargingSchedule
     if (chargingSchedule.startSchedule == null) {
@@ -804,7 +806,7 @@ const getLimitFromChargingProfiles = (
         `${logPrefix} ${moduleName}.getLimitFromChargingProfiles: Charging profile id ${chargingProfile.chargingProfileId} has no startSchedule defined. Trying to set it to the connector current transaction start date`
       )
       // OCPP specifies that if startSchedule is not defined, it should be relative to start of the connector transaction
-      chargingSchedule.startSchedule = connectorStatus.transactionStart
+      chargingSchedule.startSchedule = connectorStatus?.transactionStart
     }
     if (!isDate(chargingSchedule.startSchedule)) {
       logger.warn(
@@ -915,7 +917,7 @@ const getLimitFromChargingProfiles = (
 }
 
 export const prepareChargingProfileKind = (
-  connectorStatus: ConnectorStatus,
+  connectorStatus: ConnectorStatus | undefined,
   chargingProfile: ChargingProfile,
   currentDate: string | number | Date,
   logPrefix: string
@@ -934,7 +936,7 @@ export const prepareChargingProfileKind = (
         )
         delete chargingProfile.chargingSchedule.startSchedule
       }
-      if (connectorStatus.transactionStarted === true) {
+      if (connectorStatus?.transactionStarted === true) {
         chargingProfile.chargingSchedule.startSchedule = connectorStatus.transactionStart
       }
       // FIXME: Handle relative charging profile duration
index 2407418601bacbbc4cc4bdf290c1f1477ed04a61..b82587c4368eb566ddce5c19d23207de011e4588 100644 (file)
@@ -129,8 +129,7 @@ export class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChanne
             RequestCommand.STOP_TRANSACTION,
             {
               meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(
-                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                requestPayload!.transactionId!,
+                requestPayload?.transactionId,
                 true
               ),
               ...requestPayload
index 64d836d5f4ce6a46995f0879dab0d7afb4c31b95..3e371e8251317646887eb92983fe7ef1b0d29a21 100644 (file)
@@ -691,10 +691,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         `${chargingStation.logPrefix()} Get composite schedule with a specified rate unit is not yet supported, no conversion will be done`
       )
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const connectorStatus = chargingStation.getConnectorStatus(connectorId)!
+    const connectorStatus = chargingStation.getConnectorStatus(connectorId)
     if (
-      isEmptyArray(connectorStatus.chargingProfiles) &&
+      isEmptyArray(connectorStatus?.chargingProfiles) &&
       isEmptyArray(chargingStation.getConnectorStatus(0)?.chargingProfiles)
     ) {
       return OCPP16Constants.OCPP_RESPONSE_REJECTED
@@ -719,7 +718,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
           } has no startSchedule defined. Trying to set it to the connector current transaction start date`
         )
         // OCPP specifies that if startSchedule is not defined, it should be relative to start of the connector transaction
-        chargingProfile.chargingSchedule.startSchedule = connectorStatus.transactionStart
+        chargingProfile.chargingSchedule.startSchedule = connectorStatus?.transactionStart
       }
       if (!isDate(chargingProfile.chargingSchedule.startSchedule)) {
         logger.warn(
@@ -857,7 +856,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         ? OCPP16ChargePointStatus.Available
         : OCPP16ChargePointStatus.Unavailable
     if (connectorId === 0) {
-      let response: OCPP16ChangeAvailabilityResponse
+      let response: OCPP16ChangeAvailabilityResponse | undefined
       if (chargingStation.hasEvses) {
         for (const evseStatus of chargingStation.evses.values()) {
           response = await OCPP16ServiceUtils.changeAvailability(
@@ -1455,31 +1454,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                 }
               )
                 .catch(Constants.EMPTY_FUNCTION)
-            } else {
-              if (chargingStation.hasEvses) {
-                for (const evseStatus of chargingStation.evses.values()) {
-                  for (const [id, connectorStatus] of evseStatus.connectors) {
-                    chargingStation.ocppRequestService
-                      .requestHandler<
-                    OCPP16StatusNotificationRequest,
-                    OCPP16StatusNotificationResponse
-                    >(
-                      chargingStation,
-                      OCPP16RequestCommand.STATUS_NOTIFICATION,
-                      {
-                        connectorId: id,
-                        errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
-                        status: connectorStatus.status
-                      },
-                      {
-                        triggerMessage: true
-                      }
-                    )
-                      .catch(Constants.EMPTY_FUNCTION)
-                  }
-                }
-              } else {
-                for (const id of chargingStation.connectors.keys()) {
+            } else if (chargingStation.hasEvses) {
+              for (const evseStatus of chargingStation.evses.values()) {
+                for (const [id, connectorStatus] of evseStatus.connectors) {
                   chargingStation.ocppRequestService
                     .requestHandler<
                   OCPP16StatusNotificationRequest,
@@ -1490,7 +1467,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                     {
                       connectorId: id,
                       errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
-                      status: chargingStation.getConnectorStatus(id)?.status
+                      status: connectorStatus.status
                     },
                     {
                       triggerMessage: true
@@ -1499,6 +1476,26 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
                     .catch(Constants.EMPTY_FUNCTION)
                 }
               }
+            } else {
+              for (const [id, connectorStatus] of chargingStation.connectors) {
+                chargingStation.ocppRequestService
+                  .requestHandler<
+                OCPP16StatusNotificationRequest,
+                OCPP16StatusNotificationResponse
+                >(
+                  chargingStation,
+                  OCPP16RequestCommand.STATUS_NOTIFICATION,
+                  {
+                    connectorId: id,
+                    errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                    status: connectorStatus.status
+                  },
+                  {
+                    triggerMessage: true
+                  }
+                )
+                  .catch(Constants.EMPTY_FUNCTION)
+              }
             }
           }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY)
           return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
@@ -1563,8 +1560,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         return OCPP16Constants.OCPP_RESERVATION_RESPONSE_REJECTED
       }
       await removeExpiredReservations(chargingStation)
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      switch (chargingStation.getConnectorStatus(connectorId)!.status) {
+      switch (chargingStation.getConnectorStatus(connectorId)?.status) {
         case OCPP16ChargePointStatus.Faulted:
           response = OCPP16Constants.OCPP_RESERVATION_RESPONSE_FAULTED
           break
index 124ffba16b48a7dfaea2dbbaea9fdfefb209e27a..415254d194d637113279a12526273fa3ef51150c 100644 (file)
@@ -201,10 +201,9 @@ export class OCPP16RequestService extends OCPPRequestService {
         } as unknown as Request
       case OCPP16RequestCommand.STOP_TRANSACTION:
         chargingStation.stationInfo?.transactionDataMeterValues === true &&
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
           (connectorId = chargingStation.getConnectorIdByTransactionId(
             commandParams.transactionId as number
-          )!)
+          ))
         energyActiveImportRegister = chargingStation.getEnergyActiveImportRegisterByTransactionId(
           commandParams.transactionId as number,
           true
index 3f311ba56e2687691644f41d04720d170466f412..7c2c041d716cab84e6e645b69bcd2db9f28dd003 100644 (file)
@@ -460,29 +460,30 @@ export class OCPP16ResponseService extends OCPPResponseService {
         }
       }
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const authorizeConnectorStatus = chargingStation.getConnectorStatus(authorizeConnectorId!)
-    const authorizeConnectorIdDefined = authorizeConnectorId != null
-    if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
-      if (authorizeConnectorIdDefined) {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        authorizeConnectorStatus!.idTagAuthorized = true
+    if (authorizeConnectorId != null) {
+      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+      const authorizeConnectorStatus = chargingStation.getConnectorStatus(authorizeConnectorId)!
+      if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
+        authorizeConnectorStatus.idTagAuthorized = true
+        logger.debug(
+          `${chargingStation.logPrefix()} idTag '${
+            requestPayload.idTag
+          }' accepted on connector id ${authorizeConnectorId}`
+        )
+      } else {
+        authorizeConnectorStatus.idTagAuthorized = false
+        delete authorizeConnectorStatus.authorizeIdTag
+        logger.debug(
+          `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' rejected with status '${
+            payload.idTagInfo.status
+          }`
+        )
       }
-      logger.debug(
-        `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' accepted${
-          authorizeConnectorIdDefined ? ` on connector id ${authorizeConnectorId}` : ''
-        }`
-      )
     } else {
-      if (authorizeConnectorIdDefined) {
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        authorizeConnectorStatus!.idTagAuthorized = false
-        delete authorizeConnectorStatus?.authorizeIdTag
-      }
-      logger.debug(
-        `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' rejected with status '${
-          payload.idTagInfo.status
-        }'${authorizeConnectorIdDefined ? ` on connector id ${authorizeConnectorId}` : ''}`
+      logger.error(
+        `${chargingStation.logPrefix()} idTag '${
+          requestPayload.idTag
+        }' has no authorize request pending`
       )
     }
   }
@@ -699,8 +700,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
     connectorId: number
   ): Promise<void> {
     const connectorStatus = chargingStation.getConnectorStatus(connectorId)
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    resetConnectorStatus(connectorStatus!)
+    resetConnectorStatus(connectorStatus)
     chargingStation.stopMeterValues(connectorId)
     if (connectorStatus?.status !== OCPP16ChargePointStatus.Available) {
       await OCPP16ServiceUtils.sendAndSetConnectorStatus(
@@ -764,8 +764,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       chargingStation.powerDivider!--
     }
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    resetConnectorStatus(chargingStation.getConnectorStatus(transactionConnectorId)!)
+    resetConnectorStatus(chargingStation.getConnectorStatus(transactionConnectorId))
     chargingStation.stopMeterValues(transactionConnectorId)
     const logMsg = `${chargingStation.logPrefix()} Transaction with id ${
       requestPayload.transactionId
index e73caca4e3a9b472739d1be4b147e14c693b1f1f..414b0a8f8e720c5a1c94c9178434f39094b4c4f1 100644 (file)
@@ -120,9 +120,12 @@ export const isIdTagAuthorized = async (
       `${chargingStation.logPrefix()} The charging station expects to authorize RFID tags but nor local authorization nor remote authorization are enabled. Misbehavior may occur`
     )
   }
-  if (chargingStation.getLocalAuthListEnabled() && isIdTagLocalAuthorized(chargingStation, idTag)) {
-    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const connectorStatus = chargingStation.getConnectorStatus(connectorId)!
+  const connectorStatus = chargingStation.getConnectorStatus(connectorId)
+  if (
+    connectorStatus != null &&
+    chargingStation.getLocalAuthListEnabled() &&
+    isIdTagLocalAuthorized(chargingStation, idTag)
+  ) {
     connectorStatus.localAuthorizeIdTag = idTag
     connectorStatus.idTagLocalAuthorized = true
     return true
@@ -196,8 +199,7 @@ const checkConnectorStatusTransition = (
   connectorId: number,
   status: ConnectorStatusEnum
 ): boolean => {
-  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-  const fromStatus = chargingStation.getConnectorStatus(connectorId)!.status
+  const fromStatus = chargingStation.getConnectorStatus(connectorId)?.status
   let transitionAllowed = false
   switch (chargingStation.stationInfo?.ocppVersion) {
     case OCPPVersion.VERSION_16:
@@ -238,10 +240,9 @@ const checkConnectorStatusTransition = (
     logger.warn(
       `${chargingStation.logPrefix()} OCPP ${
         chargingStation.stationInfo.ocppVersion
-      } connector id ${connectorId} status transition from '${
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        chargingStation.getConnectorStatus(connectorId)!.status
-      }' to '${status}' is not allowed`
+      } connector id ${connectorId} status transition from '${chargingStation.getConnectorStatus(
+        connectorId
+      )?.status}' to '${status}' is not allowed`
     )
   }
   return transitionAllowed