fix: start heartbeat once
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 272abc8cb024f78a9b1dbcae445a4f7043e5720c..2d934e066ff07a58470dc6162c342491df1adb93 100644 (file)
@@ -261,14 +261,17 @@ export class ChargingStation extends EventEmitter {
   }
 
   public get wsConnectionUrl (): URL {
+    const wsConnectionBaseUrlStr = `${
+      this.stationInfo?.supervisionUrlOcppConfiguration === true &&
+      isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) &&
+      isNotEmptyString(getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value)
+        ? getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value
+        : this.configuredSupervisionUrl.href
+    }`
     return new URL(
-      `${
-        this.stationInfo?.supervisionUrlOcppConfiguration === true &&
-        isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) &&
-        isNotEmptyString(getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value)
-          ? getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey)?.value
-          : this.configuredSupervisionUrl.href
-      }/${this.stationInfo?.chargingStationId}`
+      `${wsConnectionBaseUrlStr}${
+        !wsConnectionBaseUrlStr.endsWith('/') ? '/' : ''
+      }${this.stationInfo?.chargingStationId}`
     )
   }
 
@@ -286,7 +289,7 @@ export class ChargingStation extends EventEmitter {
         readFileSync(this.templateFile, 'utf8')
       ) as ChargingStationTemplate
     } catch {
-      stationTemplate = undefined
+      // Ignore
     }
     return logPrefix(` ${getChargingStationId(this.index, stationTemplate)} |`)
   }
@@ -410,14 +413,17 @@ export class ChargingStation extends EventEmitter {
     const connectorChargingProfilesPowerLimit =
       getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId)
     return min(
-      isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower,
+      isNaN(connectorMaximumPower) ? Number.POSITIVE_INFINITY : connectorMaximumPower,
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
       isNaN(connectorAmperageLimitationPowerLimit!)
-        ? Infinity
+        ? Number.POSITIVE_INFINITY
         : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
         connectorAmperageLimitationPowerLimit!,
       // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      isNaN(connectorChargingProfilesPowerLimit!) ? Infinity : connectorChargingProfilesPowerLimit!
+      isNaN(connectorChargingProfilesPowerLimit!)
+        ? Number.POSITIVE_INFINITY
+        : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+        connectorChargingProfilesPowerLimit!
     )
   }
 
@@ -943,7 +949,7 @@ export class ChargingStation extends EventEmitter {
       )
     }
     return await this.ocppRequestService.requestHandler<
-    StopTransactionRequest,
+    Partial<StopTransactionRequest>,
     StopTransactionResponse
     >(this, RequestCommand.STOP_TRANSACTION, {
       transactionId,
@@ -1358,7 +1364,9 @@ export class ChargingStation extends EventEmitter {
       addConfigurationKey(this, StandardParametersKey.HeartbeatInterval, '0')
     }
     if (getConfigurationKey(this, StandardParametersKey.HeartBeatInterval) == null) {
-      addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', { visible: false })
+      addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', {
+        visible: false
+      })
     }
     if (
       this.stationInfo?.supervisionUrlOcppConfiguration === true &&
@@ -1376,7 +1384,9 @@ export class ChargingStation extends EventEmitter {
       isNotEmptyString(this.stationInfo.supervisionUrlOcppKey) &&
       getConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey) != null
     ) {
-      deleteConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey, { save: false })
+      deleteConfigurationKey(this, this.stationInfo.supervisionUrlOcppKey, {
+        save: false
+      })
     }
     if (
       isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
@@ -1735,7 +1745,9 @@ export class ChargingStation extends EventEmitter {
               ...(this.connectors.size > 0 && {
                 connectorsStatus: configurationData.connectorsStatus
               }),
-              ...(this.evses.size > 0 && { evsesStatus: configurationData.evsesStatus })
+              ...(this.evses.size > 0 && {
+                evsesStatus: configurationData.evsesStatus
+              })
             } satisfies ChargingStationConfiguration)
           )
           .digest('hex')
@@ -1812,12 +1824,15 @@ export class ChargingStation extends EventEmitter {
     if (this.isWebSocketConnectionOpened()) {
       this.emit(ChargingStationEvents.updated)
       logger.info(
-        `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.href} succeeded`
+        `${this.logPrefix()} Connection to OCPP server through ${
+          this.wsConnectionUrl.href
+        } succeeded`
       )
       let registrationRetryCount = 0
       if (!this.isRegistered()) {
         // Send BootNotification
         do {
+          // FIXME: duplicated assignment with the boot notification response handler
           this.bootNotificationResponse = await this.ocppRequestService.requestHandler<
           BootNotificationRequest,
           BootNotificationResponse
@@ -1847,15 +1862,7 @@ export class ChargingStation extends EventEmitter {
             this.stationInfo?.registrationMaxRetries === -1)
         )
       }
-      if (this.isRegistered()) {
-        this.emit(ChargingStationEvents.registered)
-        if (this.inAcceptedState()) {
-          this.emit(ChargingStationEvents.accepted)
-        }
-      } else {
-        if (this.inRejectedState()) {
-          this.emit(ChargingStationEvents.rejected)
-        }
+      if (!this.isRegistered()) {
         logger.error(
           `${this.logPrefix()} Registration failure: maximum retries reached (${registrationRetryCount}) or retry disabled (${
             this.stationInfo?.registrationMaxRetries
@@ -2071,7 +2078,9 @@ export class ChargingStation extends EventEmitter {
           // eslint-disable-next-line @typescript-eslint/no-base-to-string
         }' message '${data.toString()}'${
           this.requests.has(messageId)
-            ? ` matching cached request '${JSON.stringify(this.getCachedRequest(messageType, messageId))}'`
+            ? ` matching cached request '${JSON.stringify(
+                this.getCachedRequest(messageType, messageId)
+              )}'`
             : ''
         } processing error:`,
         error
@@ -2215,27 +2224,38 @@ export class ChargingStation extends EventEmitter {
     // Start WebSocket ping
     this.startWebSocketPing()
     // Start heartbeat
-    this.startHeartbeat()
+    if (this.heartbeatSetInterval == null) {
+      this.startHeartbeat()
+    } else if (this.getHeartbeatInterval() !== this.bootNotificationResponse?.interval) {
+      this.restartHeartbeat()
+    }
     // Initialize connectors status
     if (this.hasEvses) {
       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)
         }
       }
     }