build(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 6513f68b19e3d8397bb999bd5f7bf0c661e8f311..9efe7b3087fac1a46136255fe050e88966ba00a0 100644 (file)
@@ -169,8 +169,8 @@ export class ChargingStation extends EventEmitter {
   public performanceStatistics!: PerformanceStatistics | undefined
   public heartbeatSetInterval?: NodeJS.Timeout
   public ocppRequestService!: OCPPRequestService
-  public bootNotificationRequest!: BootNotificationRequest
-  public bootNotificationResponse!: BootNotificationResponse | undefined
+  public bootNotificationRequest?: BootNotificationRequest
+  public bootNotificationResponse?: BootNotificationResponse
   public powerDivider?: number
   private stopping: boolean
   private configurationFile!: string
@@ -238,8 +238,12 @@ export class ChargingStation extends EventEmitter {
   }
 
   public logPrefix = (): string => {
-    if (isNotEmptyString(this.stationInfo?.chargingStationId)) {
-      return logPrefix(` ${this.stationInfo?.chargingStationId} |`)
+    if (
+      this instanceof ChargingStation &&
+      this.stationInfo != null &&
+      isNotEmptyString(this.stationInfo.chargingStationId)
+    ) {
+      return logPrefix(` ${this.stationInfo.chargingStationId} |`)
     }
     let stationTemplate: ChargingStationTemplate | undefined
     try {
@@ -259,7 +263,7 @@ export class ChargingStation extends EventEmitter {
 
   public getNumberOfPhases (stationInfo?: ChargingStationInfo): number {
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const localStationInfo: ChargingStationInfo = stationInfo ?? this.stationInfo!
+    const localStationInfo = stationInfo ?? this.stationInfo!
     switch (this.getCurrentOutType(stationInfo)) {
       case CurrentType.AC:
         return localStationInfo.numberOfPhases ?? 3
@@ -346,10 +350,11 @@ export class ChargingStation extends EventEmitter {
 
   public getConnectorMaximumAvailablePower (connectorId: number): number {
     let connectorAmperageLimitationPowerLimit: number | undefined
+    const amperageLimitation = this.getAmperageLimitation()
     if (
-      this.getAmperageLimitation() != null &&
+      amperageLimitation != null &&
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      this.getAmperageLimitation()! < this.stationInfo!.maximumAmperage!
+      amperageLimitation < this.stationInfo!.maximumAmperage!
     ) {
       connectorAmperageLimitationPowerLimit =
         (this.stationInfo?.currentOutType === CurrentType.AC
@@ -357,12 +362,11 @@ export class ChargingStation extends EventEmitter {
             this.getNumberOfPhases(),
             // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
             this.stationInfo.voltageOut!,
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            this.getAmperageLimitation()! *
+            amperageLimitation *
                 (this.hasEvses ? this.getNumberOfEvses() : this.getNumberOfConnectors())
           )
           : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          DCElectricUtils.power(this.stationInfo!.voltageOut!, this.getAmperageLimitation()!)) /
+          DCElectricUtils.power(this.stationInfo!.voltageOut!, amperageLimitation)) /
         // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         this.powerDivider!
     }
@@ -423,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) {
@@ -442,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 {
@@ -513,7 +518,7 @@ export class ChargingStation extends EventEmitter {
       this.heartbeatSetInterval = setInterval(() => {
         this.ocppRequestService
           .requestHandler<HeartbeatRequest, HeartbeatResponse>(this, RequestCommand.HEARTBEAT)
-          .catch((error) => {
+          .catch(error => {
             logger.error(
               `${this.logPrefix()} Error while sending '${RequestCommand.HEARTBEAT}':`,
               error
@@ -557,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`
@@ -579,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
@@ -594,11 +599,11 @@ export class ChargingStation extends EventEmitter {
           RequestCommand.METER_VALUES,
           {
             connectorId,
-            transactionId: this.getConnectorStatus(connectorId)?.transactionId,
+            transactionId: connectorStatus.transactionId,
             meterValue: [meterValue]
           }
         )
-          .catch((error) => {
+          .catch(error => {
             logger.error(
               `${this.logPrefix()} Error while sending '${RequestCommand.METER_VALUES}':`,
               error
@@ -615,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)
     }
   }
 
@@ -864,8 +870,7 @@ export class ChargingStation extends EventEmitter {
       const transactionEndMeterValue = buildTransactionEndMeterValue(
         this,
         connectorId,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.getEnergyActiveImportRegisterByTransactionId(transactionId!)
+        this.getEnergyActiveImportRegisterByTransactionId(transactionId)
       )
       await this.ocppRequestService.requestHandler<MeterValuesRequest, MeterValuesResponse>(
         this,
@@ -882,8 +887,7 @@ export class ChargingStation extends EventEmitter {
     StopTransactionResponse
     >(this, RequestCommand.STOP_TRANSACTION, {
       transactionId,
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId!, true),
+      meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId, true),
       ...(reason != null && { reason })
     })
   }
@@ -1089,14 +1093,14 @@ export class ChargingStation extends EventEmitter {
 
   private getStationInfoFromTemplate (): ChargingStationInfo {
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    const stationTemplate: ChargingStationTemplate = this.getTemplateFromFile()!
+    const stationTemplate = this.getTemplateFromFile()!
     checkTemplate(stationTemplate, this.logPrefix(), this.templateFile)
     const warnTemplateKeysDeprecationOnce = once(warnTemplateKeysDeprecation, this)
     warnTemplateKeysDeprecationOnce(stationTemplate, this.logPrefix(), this.templateFile)
     if (stationTemplate.Connectors != null) {
       checkConnectorsConfiguration(stationTemplate, this.logPrefix(), this.templateFile)
     }
-    const stationInfo: ChargingStationInfo = stationTemplateToStationInfo(stationTemplate)
+    const stationInfo = stationTemplateToStationInfo(stationTemplate)
     stationInfo.hashId = getHashId(this.index, stationTemplate)
     stationInfo.chargingStationId = getChargingStationId(this.index, stationTemplate)
     stationInfo.ocppVersion = stationTemplate.ocppVersion ?? OCPPVersion.VERSION_16
@@ -1161,16 +1165,18 @@ export class ChargingStation extends EventEmitter {
 
   private getStationInfo (): ChargingStationInfo {
     const defaultStationInfo = Constants.DEFAULT_STATION_INFO
-    const stationInfoFromTemplate: ChargingStationInfo = this.getStationInfoFromTemplate()
-    const stationInfoFromFile: ChargingStationInfo | undefined = this.getStationInfoFromFile(
+    const stationInfoFromTemplate = this.getStationInfoFromTemplate()
+    const stationInfoFromFile = this.getStationInfoFromFile(
       stationInfoFromTemplate.stationInfoPersistentConfiguration
     )
     // Priority:
     // 1. charging station info from template
     // 2. charging station info from configuration file
-    if (stationInfoFromFile?.templateHash === stationInfoFromTemplate.templateHash) {
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      return { ...defaultStationInfo, ...stationInfoFromFile! }
+    if (
+      stationInfoFromFile != null &&
+      stationInfoFromFile.templateHash === stationInfoFromTemplate.templateHash
+    ) {
+      return { ...defaultStationInfo, ...stationInfoFromFile }
     }
     stationInfoFromFile != null &&
       propagateSerialNumber(
@@ -1217,7 +1223,7 @@ export class ChargingStation extends EventEmitter {
       isNotEmptyString(this.stationInfo.firmwareVersion) &&
       isNotEmptyString(this.stationInfo.firmwareVersionPattern)
     ) {
-      const patternGroup: number | undefined =
+      const patternGroup =
         this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ??
         this.stationInfo.firmwareVersion?.split('.').length
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1241,19 +1247,24 @@ export class ChargingStation extends EventEmitter {
     if (this.stationInfo.enableStatistics === true) {
       this.performanceStatistics = PerformanceStatistics.getInstance(
         this.stationInfo.hashId,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.stationInfo.chargingStationId!,
+        this.stationInfo.chargingStationId,
         this.configuredSupervisionUrl
       )
     }
-    this.bootNotificationRequest = createBootNotificationRequest(this.stationInfo)
+    const bootNotificationRequest = createBootNotificationRequest(this.stationInfo)
+    if (bootNotificationRequest == null) {
+      const errorMsg = 'Error while creating boot notification request'
+      logger.error(`${this.logPrefix()} ${errorMsg}`)
+      throw new BaseError(errorMsg)
+    }
+    this.bootNotificationRequest = bootNotificationRequest
     this.powerDivider = this.getPowerDivider()
     // OCPP configuration
     this.ocppConfiguration = this.getOcppConfiguration()
     this.initializeOcppConfiguration()
     this.initializeOcppServices()
     this.once(ChargingStationEvents.accepted, () => {
-      this.startMessageSequence().catch((error) => {
+      this.startMessageSequence().catch(error => {
         logger.error(`${this.logPrefix()} Error while starting the message sequence:`, error)
       })
     })
@@ -1322,7 +1333,7 @@ export class ChargingStation extends EventEmitter {
     if (
       isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      getConfigurationKey(this, this.stationInfo!.amperageLimitationOcppKey!) == null
+      getConfigurationKey(this, this.stationInfo.amperageLimitationOcppKey!) == null
     ) {
       addConfigurationKey(
         this,
@@ -1633,10 +1644,10 @@ export class ChargingStation extends EventEmitter {
         if (!existsSync(dirname(this.configurationFile))) {
           mkdirSync(dirname(this.configurationFile), { recursive: true })
         }
+        const configurationFromFile = this.getConfigurationFromFile()
         let configurationData: ChargingStationConfiguration =
-          this.getConfigurationFromFile() != null
-            ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()!)
+          configurationFromFile != null
+            ? cloneObject<ChargingStationConfiguration>(configurationFromFile)
             : {}
         if (this.stationInfo?.stationInfoPersistentConfiguration === true) {
           configurationData.stationInfo = this.stationInfo
@@ -1699,7 +1710,7 @@ export class ChargingStation extends EventEmitter {
             this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash)
             this.sharedLRUCache.setChargingStationConfiguration(configurationData)
             this.configurationFileHash = configurationHash
-          }).catch((error) => {
+          }).catch(error => {
             handleFileException(
               this.configurationFile,
               FileType.ChargingStationConfiguration,
@@ -1769,7 +1780,7 @@ export class ChargingStation extends EventEmitter {
             this.stationInfo?.registrationMaxRetries !== -1 && ++registrationRetryCount
             await sleep(
               // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
-              this.bootNotificationResponse.interval != null
+              this.bootNotificationResponse?.interval != null
                 ? secondsToMilliseconds(this.bootNotificationResponse.interval)
                 : Constants.DEFAULT_BOOT_NOTIFICATION_INTERVAL
             )
@@ -1788,8 +1799,9 @@ export class ChargingStation extends EventEmitter {
         }
       } else {
         logger.error(
-          `${this.logPrefix()} Registration failure: maximum retries reached (${registrationRetryCount}) or retry disabled (${this
-            .stationInfo?.registrationMaxRetries})`
+          `${this.logPrefix()} Registration failure: maximum retries reached (${registrationRetryCount}) or retry disabled (${
+            this.stationInfo?.registrationMaxRetries
+          })`
         )
       }
       this.autoReconnectRetryCount = 0
@@ -2008,20 +2020,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
     )
   }
 
@@ -2219,7 +2236,7 @@ export class ChargingStation extends EventEmitter {
   }
 
   private startWebSocketPing (): void {
-    const webSocketPingInterval: number =
+    const webSocketPingInterval =
       getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval) != null
         ? convertToInt(
           getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval)?.value