refactor: cleanup reservation handling code
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index ace7aff1cfb67c29f6c291cdee78bbc7b659a977..fc6a409adfc006c7200bc600441f83c8ebeb1490 100644 (file)
@@ -26,7 +26,6 @@ import {
   type OCPPRequestService,
   OCPPServiceUtils,
 } from './ocpp';
-import { OCPPConstants } from './ocpp/OCPPConstants';
 import { SharedLRUCache } from './SharedLRUCache';
 import { BaseError, OCPPError } from '../exception';
 import { PerformanceStatistics } from '../performance';
@@ -63,15 +62,17 @@ import {
   MeterValueMeasurand,
   type MeterValuesRequest,
   type MeterValuesResponse,
-  OCPP16SupportedFeatureProfiles,
-  OCPP20ConnectorStatusEnumType,
   OCPPVersion,
   type OutgoingRequest,
   PowerUnits,
   RegistrationStatusEnumType,
   RequestCommand,
+  type Reservation,
+  ReservationFilterKey,
+  ReservationTerminationReason,
   type Response,
   StandardParametersKey,
+  type Status,
   type StatusNotificationRequest,
   type StatusNotificationResponse,
   StopTransactionReason,
@@ -84,7 +85,6 @@ import {
   WebSocketCloseEventStatusCode,
   type WsOptions,
 } from '../types';
-import type { Reservation } from '../types/ocpp/Reservation';
 import {
   ACElectricUtils,
   AsyncLock,
@@ -92,14 +92,16 @@ import {
   Configuration,
   Constants,
   DCElectricUtils,
-  ErrorUtils,
-  FileUtils,
-  MessageChannelUtils,
   Utils,
   buildChargingStationAutomaticTransactionGeneratorConfiguration,
   buildConnectorsStatus,
   buildEvsesStatus,
+  buildStartedMessage,
+  buildStoppedMessage,
+  buildUpdatedMessage,
+  handleFileException,
   logger,
+  watchJsonFile,
 } from '../utils';
 
 export class ChargingStation {
@@ -136,7 +138,7 @@ export class ChargingStation {
   private readonly sharedLRUCache: SharedLRUCache;
   private webSocketPingSetInterval!: NodeJS.Timeout;
   private readonly chargingStationWorkerBroadcastChannel: ChargingStationWorkerBroadcastChannel;
-  private reservations?: Reservation[];
+  private reservationExpirationSetInterval?: NodeJS.Timeout;
 
   constructor(index: number, templateFile: string) {
     this.started = false;
@@ -553,7 +555,8 @@ export class ChargingStation {
       );
     } else {
       logger.error(
-        `${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval()}, not starting the heartbeat`
+        `${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval()},
+          not starting the heartbeat`
       );
     }
   }
@@ -581,13 +584,15 @@ export class ChargingStation {
     }
     if (!this.getConnectorStatus(connectorId)) {
       logger.error(
-        `${this.logPrefix()} Trying to start MeterValues on non existing connector id ${connectorId.toString()}`
+        `${this.logPrefix()} Trying to start MeterValues on non existing connector id
+          ${connectorId.toString()}`
       );
       return;
     }
     if (this.getConnectorStatus(connectorId)?.transactionStarted === false) {
       logger.error(
-        `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId} with no transaction started`
+        `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId}
+          with no transaction started`
       );
       return;
     } else if (
@@ -595,7 +600,8 @@ export class ChargingStation {
       Utils.isNullOrUndefined(this.getConnectorStatus(connectorId)?.transactionId)
     ) {
       logger.error(
-        `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId} with no transaction id`
+        `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId}
+          with no transaction id`
       );
       return;
     }
@@ -647,9 +653,12 @@ export class ChargingStation {
         if (this.getEnableStatistics() === true) {
           this.performanceStatistics?.start();
         }
+        if (this.hasFeatureProfile(SupportedFeatureProfiles.Reservation)) {
+          this.startReservationExpirationSetInterval();
+        }
         this.openWSConnection();
         // Monitor charging station template file
-        this.templateFileWatcher = FileUtils.watchJsonFile(
+        this.templateFileWatcher = watchJsonFile(
           this.templateFile,
           FileType.ChargingStationTemplate,
           this.logPrefix(),
@@ -686,7 +695,7 @@ export class ChargingStation {
           }
         );
         this.started = true;
-        parentPort?.postMessage(MessageChannelUtils.buildStartedMessage(this));
+        parentPort?.postMessage(buildStartedMessage(this));
         this.starting = false;
       } else {
         logger.warn(`${this.logPrefix()} Charging station is already starting...`);
@@ -711,7 +720,7 @@ export class ChargingStation {
         delete this.bootNotificationResponse;
         this.started = false;
         this.saveConfiguration();
-        parentPort?.postMessage(MessageChannelUtils.buildStoppedMessage(this));
+        parentPort?.postMessage(buildStoppedMessage(this));
         this.stopping = false;
       } else {
         logger.warn(`${this.logPrefix()} Charging station is already stopping...`);
@@ -752,11 +761,12 @@ export class ChargingStation {
       terminateOpened: false,
     }
   ): void {
-    options.handshakeTimeout = options?.handshakeTimeout ?? this.getConnectionTimeout() * 1000;
+    options = { handshakeTimeout: this.getConnectionTimeout() * 1000, ...options };
     params = { ...{ closeOpened: false, terminateOpened: false }, ...params };
     if (this.started === false && this.starting === false) {
       logger.warn(
-        `${this.logPrefix()} Cannot open OCPP connection to URL ${this.wsConnectionUrl.toString()} on stopped charging station`
+        `${this.logPrefix()} Cannot open OCPP connection to URL ${this.wsConnectionUrl.toString()}
+          on stopped charging station`
       );
       return;
     }
@@ -775,7 +785,8 @@ export class ChargingStation {
 
     if (this.isWebSocketConnectionOpened() === true) {
       logger.warn(
-        `${this.logPrefix()} OCPP connection to URL ${this.wsConnectionUrl.toString()} is already opened`
+        `${this.logPrefix()} OCPP connection to URL ${this.wsConnectionUrl.toString()}
+          is already opened`
       );
       return;
     }
@@ -823,12 +834,29 @@ export class ChargingStation {
   public getAutomaticTransactionGeneratorConfiguration():
     | AutomaticTransactionGeneratorConfiguration
     | undefined {
+    let automaticTransactionGeneratorConfiguration:
+      | AutomaticTransactionGeneratorConfiguration
+      | undefined;
     const automaticTransactionGeneratorConfigurationFromFile =
       this.getConfigurationFromFile()?.automaticTransactionGenerator;
-    if (automaticTransactionGeneratorConfigurationFromFile) {
-      return automaticTransactionGeneratorConfigurationFromFile;
+    if (
+      this.getAutomaticTransactionGeneratorPersistentConfiguration() &&
+      automaticTransactionGeneratorConfigurationFromFile
+    ) {
+      automaticTransactionGeneratorConfiguration =
+        automaticTransactionGeneratorConfigurationFromFile;
+    } else {
+      automaticTransactionGeneratorConfiguration =
+        this.getTemplateFromFile()?.AutomaticTransactionGenerator;
     }
-    return this.getTemplateFromFile()?.AutomaticTransactionGenerator;
+    return {
+      ...Constants.DEFAULT_ATG_CONFIGURATION,
+      ...automaticTransactionGeneratorConfiguration,
+    };
+  }
+
+  public getAutomaticTransactionGeneratorStatuses(): Status[] | undefined {
+    return this.getConfigurationFromFile()?.automaticTransactionGeneratorStatuses;
   }
 
   public startAutomaticTransactionGenerator(connectorIds?: number[]): void {
@@ -840,8 +868,8 @@ export class ChargingStation {
     } else {
       this.automaticTransactionGenerator?.start();
     }
-    this.saveChargingStationAutomaticTransactionGeneratorConfiguration();
-    parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
+    this.saveAutomaticTransactionGeneratorConfiguration();
+    parentPort?.postMessage(buildUpdatedMessage(this));
   }
 
   public stopAutomaticTransactionGenerator(connectorIds?: number[]): void {
@@ -852,8 +880,8 @@ export class ChargingStation {
     } else {
       this.automaticTransactionGenerator?.stop();
     }
-    this.saveChargingStationAutomaticTransactionGeneratorConfiguration();
-    parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
+    this.saveAutomaticTransactionGeneratorConfiguration();
+    parentPort?.postMessage(buildUpdatedMessage(this));
   }
 
   public async stopTransactionOnConnector(
@@ -893,78 +921,197 @@ export class ChargingStation {
     );
   }
 
-  public supportsReservations(): boolean {
-    logger.info(`${this.logPrefix()} Check for reservation support in charging station`);
-    return ChargingStationConfigurationUtils.getConfigurationKey(
-      this,
-      StandardParametersKey.SupportedFeatureProfiles
-    ).value.includes(OCPP16SupportedFeatureProfiles.Reservation);
-  }
-
-  public supportsReservationsOnConnectorId0(): boolean {
-    logger.info(
-      `Check for reservation support on connector 0 in charging station (CS): ${this.logPrefix()}`
-    );
-    return (
-      this.supportsReservations() &&
+  public getReservationOnConnectorId0Enabled(): boolean {
+    return Utils.convertToBoolean(
       ChargingStationConfigurationUtils.getConfigurationKey(
         this,
-        OCPPConstants.OCPP_RESERVE_CONNECTOR_ZERO_SUPPORTED
-      ).value === 'true'
+        StandardParametersKey.ReserveConnectorZeroSupported
+      ).value
     );
   }
 
-  public addReservation(newReservation: Reservation): void {
-    if (Utils.isNullOrUndefined(this.reservations)) {
-      this.reservations = [];
-    }
-    const [exists, foundReservation] = this.doesReservationExist(newReservation.reservationId);
+  public async addReservation(reservation: Reservation): Promise<void> {
+    const [exists, reservationFound] = this.doesReservationExists(reservation);
     if (exists) {
-      this.replaceExistingReservation(foundReservation, newReservation);
-    } else {
-      this.reservations.push(newReservation);
+      await this.removeReservation(reservationFound);
+    }
+    const connectorStatus = this.getConnectorStatus(reservation.connectorId);
+    connectorStatus.reservation = reservation;
+    connectorStatus.status = ConnectorStatusEnum.Reserved;
+    if (reservation.connectorId === 0) {
+      return;
     }
+    await this.ocppRequestService.requestHandler<
+      StatusNotificationRequest,
+      StatusNotificationResponse
+    >(
+      this,
+      RequestCommand.STATUS_NOTIFICATION,
+      OCPPServiceUtils.buildStatusNotificationRequest(
+        this,
+        reservation.connectorId,
+        ConnectorStatusEnum.Reserved
+      )
+    );
   }
 
-  public removeReservation(existingReservationId: number): void {
-    const index = this.reservations.findIndex((res) => res.reservationId === existingReservationId);
-    this.reservations.splice(index, 1);
+  public async removeReservation(
+    reservation: Reservation,
+    reason?: ReservationTerminationReason
+  ): Promise<void> {
+    const connector = this.getConnectorStatus(reservation.connectorId);
+    switch (reason) {
+      case ReservationTerminationReason.TRANSACTION_STARTED: {
+        delete connector.reservation;
+        if (reservation.connectorId === 0) {
+          connector.status = ConnectorStatusEnum.Available;
+        }
+        break;
+      }
+      case ReservationTerminationReason.CONNECTOR_STATE_CHANGED: {
+        delete connector.reservation;
+        break;
+      }
+      default: {
+        // ReservationTerminationReason.EXPIRED, ReservationTerminationReason.CANCELED
+        connector.status = ConnectorStatusEnum.Available;
+        delete connector.reservation;
+        await this.ocppRequestService.requestHandler<
+          StatusNotificationRequest,
+          StatusNotificationResponse
+        >(
+          this,
+          RequestCommand.STATUS_NOTIFICATION,
+          OCPPServiceUtils.buildStatusNotificationRequest(
+            this,
+            reservation.connectorId,
+            ConnectorStatusEnum.Available
+          )
+        );
+        break;
+      }
+    }
   }
 
-  public getReservation(reservationId: number, reservationIndex?: number): Reservation {
-    if (!Utils.isNullOrUndefined(reservationIndex)) {
-      return this.reservations[reservationIndex];
+  public getReservationBy(filterKey: ReservationFilterKey, value: number | string): Reservation {
+    if (this.hasEvses) {
+      for (const evse of this.evses.values()) {
+        for (const connector of evse.connectors.values()) {
+          if (connector?.reservation?.[filterKey] === value) {
+            return connector.reservation;
+          }
+        }
+      }
+    } else {
+      for (const connector of this.connectors.values()) {
+        if (connector?.reservation?.[filterKey] === value) {
+          return connector.reservation;
+        }
+      }
     }
-    return this.reservations.find((r) => r.reservationId === reservationId);
   }
 
-  public doesReservationExist(
-    reservationId: number,
-    reservation?: Reservation
-  ): [boolean, Reservation] {
-    const foundReservation = this.reservations.find(
-      (r) => r.reservationId === reservationId || r.reservationId === reservation.reservationId
+  public doesReservationExists(reservation: Partial<Reservation>): [boolean, Reservation] {
+    const foundReservation = this.getReservationBy(
+      ReservationFilterKey.RESERVATION_ID,
+      reservation?.id
     );
     return Utils.isUndefined(foundReservation) ? [false, null] : [true, foundReservation];
   }
 
-  public getReservationByConnectorId(connectorId: number): Reservation {
-    return this.reservations.find((r) => r.connectorId === connectorId);
+  public startReservationExpirationSetInterval(customInterval?: number): void {
+    const interval =
+      customInterval ?? Constants.DEFAULT_RESERVATION_EXPIRATION_OBSERVATION_INTERVAL;
+    logger.info(
+      `${this.logPrefix()} Reservation expiration date interval is set to ${interval}
+        and starts on charging station now`
+    );
+    // eslint-disable-next-line @typescript-eslint/no-misused-promises
+    this.reservationExpirationSetInterval = setInterval(async (): Promise<void> => {
+      if (this.hasEvses) {
+        for (const evse of this.evses.values()) {
+          for (const connector of evse.connectors.values()) {
+            if (connector?.reservation?.expiryDate.toString() < new Date().toISOString()) {
+              await this.removeReservation(connector.reservation);
+            }
+          }
+        }
+      } else {
+        for (const connector of this.connectors.values()) {
+          if (connector?.reservation?.expiryDate.toString() < new Date().toISOString()) {
+            await this.removeReservation(connector.reservation);
+          }
+        }
+      }
+    }, interval);
+  }
+
+  public restartReservationExpiryDateSetInterval(): void {
+    this.stopReservationExpirationSetInterval();
+    this.startReservationExpirationSetInterval();
+  }
+
+  public validateIncomingRequestWithReservation(connectorId: number, idTag: string): boolean {
+    const reservation = this.getReservationBy(ReservationFilterKey.CONNECTOR_ID, connectorId);
+    return !Utils.isUndefined(reservation) && reservation.idTag === idTag;
   }
 
-  public getAvailableConnector(): Map<number, ConnectorStatus> {
-    for (const connectorId in this.connectors) {
-      // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
-      const connector = this.connectors[Utils.convertToInt(connectorId)];
-      if (
-        this.isConnectorAvailable(Utils.convertToInt(connectorId)) &&
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-        connector.status === OCPP20ConnectorStatusEnumType.Available
-      ) {
-        // eslint-disable-next-line @typescript-eslint/no-unsafe-return
-        return connector;
+  public isConnectorReservable(
+    reservationId: number,
+    idTag?: string,
+    connectorId?: number
+  ): boolean {
+    const [alreadyExists] = this.doesReservationExists({ id: reservationId });
+    if (alreadyExists) {
+      return alreadyExists;
+    }
+    const userReservedAlready = Utils.isUndefined(
+      this.getReservationBy(ReservationFilterKey.ID_TAG, idTag)
+    )
+      ? false
+      : true;
+    const notConnectorZero = Utils.isUndefined(connectorId) ? true : connectorId > 0;
+    const freeConnectorsAvailable = this.getNumberOfReservableConnectors() > 0;
+    return !alreadyExists && !userReservedAlready && notConnectorZero && freeConnectorsAvailable;
+  }
+
+  private getNumberOfReservableConnectors(): number {
+    let reservableConnectors = 0;
+    if (this.hasEvses) {
+      for (const evse of this.evses.values()) {
+        reservableConnectors = this.countReservableConnectors(evse.connectors);
+      }
+    } else {
+      reservableConnectors = this.countReservableConnectors(this.connectors);
+    }
+    return reservableConnectors - this.getNumberOfReservationsOnConnectorZero();
+  }
+
+  private countReservableConnectors(connectors: Map<number, ConnectorStatus>) {
+    let reservableConnectors = 0;
+    for (const [connectorId, connector] of connectors) {
+      if (connectorId === 0) {
+        continue;
+      }
+      if (connector.status === ConnectorStatusEnum.Available) {
+        ++reservableConnectors;
       }
     }
+    return reservableConnectors;
+  }
+
+  private getNumberOfReservationsOnConnectorZero(): number {
+    let numberOfReservations = 0;
+    if (this.hasEvses) {
+      for (const evse of this.evses.values()) {
+        if (evse.connectors.get(0)?.reservation) {
+          ++numberOfReservations;
+        }
+      }
+    } else if (this.connectors.get(0)?.reservation) {
+      ++numberOfReservations;
+    }
+    return numberOfReservations;
   }
 
   private flushMessageBuffer(): void {
@@ -994,14 +1141,10 @@ export class ChargingStation {
     return this.stationInfo.supervisionUrlOcppConfiguration ?? false;
   }
 
-  private replaceExistingReservation(
-    existingReservation: Reservation,
-    newReservation: Reservation
-  ): void {
-    const existingReservationIndex = this.reservations.findIndex(
-      (r) => r.reservationId === existingReservation.reservationId
-    );
-    this.reservations.splice(existingReservationIndex, 1, newReservation);
+  private stopReservationExpirationSetInterval(): void {
+    if (this.reservationExpirationSetInterval) {
+      clearInterval(this.reservationExpirationSetInterval);
+    }
   }
 
   private getSupervisionUrlOcppKey(): string {
@@ -1028,7 +1171,7 @@ export class ChargingStation {
         this.templateFileHash = template.templateHash;
       }
     } catch (error) {
-      ErrorUtils.handleFileException(
+      handleFileException(
         this.templateFile,
         FileType.ChargingStationTemplate,
         error as NodeJS.ErrnoException,
@@ -1147,8 +1290,13 @@ export class ChargingStation {
     return this.stationInfo?.stationInfoPersistentConfiguration ?? true;
   }
 
+  private getAutomaticTransactionGeneratorPersistentConfiguration(): boolean {
+    return this.stationInfo?.automaticTransactionGeneratorPersistentConfiguration ?? true;
+  }
+
   private handleUnsupportedVersion(version: OCPPVersion) {
-    const errorMsg = `Unsupported protocol version '${version}' configured in template file ${this.templateFile}`;
+    const errorMsg = `Unsupported protocol version '${version}' configured
+      in template file ${this.templateFile}`;
     logger.error(`${this.logPrefix()} ${errorMsg}`);
     throw new BaseError(errorMsg);
   }
@@ -1161,9 +1309,8 @@ export class ChargingStation {
       `${ChargingStationUtils.getHashId(this.index, stationTemplate)}.json`
     );
     const chargingStationConfiguration = this.getConfigurationFromFile();
-    const featureFlag = false;
     if (
-      featureFlag &&
+      chargingStationConfiguration?.stationInfo?.templateHash === stationTemplate?.templateHash &&
       (chargingStationConfiguration?.connectorsStatus || chargingStationConfiguration?.evsesStatus)
     ) {
       this.initializeConnectorsOrEvsesFromFile(chargingStationConfiguration);
@@ -1546,7 +1693,7 @@ export class ChargingStation {
     if (stationTemplate?.Evses) {
       const evsesConfigHash = crypto
         .createHash(Constants.DEFAULT_HASH_ALGORITHM)
-        .update(`${JSON.stringify(stationTemplate?.Evses)}`)
+        .update(JSON.stringify(stationTemplate?.Evses))
         .digest('hex');
       const evsesConfigChanged =
         this.evses?.size !== 0 && this.evsesConfigurationHash !== evsesConfigHash;
@@ -1607,7 +1754,7 @@ export class ChargingStation {
           this.configurationFileHash = configuration.configurationHash;
         }
       } catch (error) {
-        ErrorUtils.handleFileException(
+        handleFileException(
           this.configurationFile,
           FileType.ChargingStationConfiguration,
           error as NodeJS.ErrnoException,
@@ -1618,8 +1765,10 @@ export class ChargingStation {
     return configuration;
   }
 
-  private saveChargingStationAutomaticTransactionGeneratorConfiguration(): void {
-    this.saveConfiguration();
+  private saveAutomaticTransactionGeneratorConfiguration(): void {
+    if (this.getAutomaticTransactionGeneratorPersistentConfiguration()) {
+      this.saveConfiguration();
+    }
   }
 
   private saveConnectorsStatus() {
@@ -1640,24 +1789,44 @@ export class ChargingStation {
           Utils.cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()) ?? {};
         if (this.getStationInfoPersistentConfiguration() && this.stationInfo) {
           configurationData.stationInfo = this.stationInfo;
+        } else {
+          delete configurationData.stationInfo;
         }
         if (this.getOcppPersistentConfiguration() && this.ocppConfiguration?.configurationKey) {
           configurationData.configurationKey = this.ocppConfiguration.configurationKey;
+        } else {
+          delete configurationData.configurationKey;
         }
         configurationData = merge<ChargingStationConfiguration>(
           configurationData,
           buildChargingStationAutomaticTransactionGeneratorConfiguration(this)
         );
+        if (
+          !this.getAutomaticTransactionGeneratorPersistentConfiguration() ||
+          !this.getAutomaticTransactionGeneratorConfiguration()
+        ) {
+          delete configurationData.automaticTransactionGenerator;
+        }
         if (this.connectors.size > 0) {
           configurationData.connectorsStatus = buildConnectorsStatus(this);
+        } else {
+          delete configurationData.connectorsStatus;
         }
         if (this.evses.size > 0) {
           configurationData.evsesStatus = buildEvsesStatus(this);
+        } else {
+          delete configurationData.evsesStatus;
         }
         delete configurationData.configurationHash;
         const configurationHash = crypto
           .createHash(Constants.DEFAULT_HASH_ALGORITHM)
-          .update(JSON.stringify(configurationData))
+          .update(
+            JSON.stringify({
+              stationInfo: configurationData.stationInfo,
+              configurationKey: configurationData.configurationKey,
+              automaticTransactionGenerator: configurationData.automaticTransactionGenerator,
+            } as ChargingStationConfiguration)
+          )
           .digest('hex');
         if (this.configurationFileHash !== configurationHash) {
           AsyncLock.acquire(AsyncLockType.configuration)
@@ -1674,7 +1843,7 @@ export class ChargingStation {
               this.configurationFileHash = configurationHash;
             })
             .catch((error) => {
-              ErrorUtils.handleFileException(
+              handleFileException(
                 this.configurationFile,
                 FileType.ChargingStationConfiguration,
                 error as NodeJS.ErrnoException,
@@ -1692,7 +1861,7 @@ export class ChargingStation {
           );
         }
       } catch (error) {
-        ErrorUtils.handleFileException(
+        handleFileException(
           this.configurationFile,
           FileType.ChargingStationConfiguration,
           error as NodeJS.ErrnoException,
@@ -1743,7 +1912,7 @@ export class ChargingStation {
             skipBufferingOnError: true,
           });
           if (this.isRegistered() === false) {
-            this.getRegistrationMaxRetries() !== -1 && registrationRetryCount++;
+            this.getRegistrationMaxRetries() !== -1 && ++registrationRetryCount;
             await Utils.sleep(
               this?.bootNotificationResponse?.interval
                 ? this.bootNotificationResponse.interval * 1000
@@ -1767,7 +1936,7 @@ export class ChargingStation {
       }
       this.wsConnectionRestarted = false;
       this.autoReconnectRetryCount = 0;
-      parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
+      parentPort?.postMessage(buildUpdatedMessage(this));
     } else {
       logger.warn(
         `${this.logPrefix()} Connection to OCPP server through ${this.wsConnectionUrl.toString()} failed`
@@ -1797,7 +1966,7 @@ export class ChargingStation {
         this.started === true && (await this.reconnect());
         break;
     }
-    parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
+    parentPort?.postMessage(buildUpdatedMessage(this));
   }
 
   private getCachedRequest(messageType: MessageType, messageId: string): CachedRequest | undefined {
@@ -1907,7 +2076,7 @@ export class ChargingStation {
             logger.error(`${this.logPrefix()} ${errorMsg}`);
             throw new OCPPError(ErrorType.PROTOCOL_ERROR, errorMsg);
         }
-        parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
+        parentPort?.postMessage(buildUpdatedMessage(this));
       } else {
         throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming message is not an array', null, {
           request,
@@ -2305,7 +2474,7 @@ export class ChargingStation {
       this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() ||
       this.getAutoReconnectMaxRetries() === -1
     ) {
-      this.autoReconnectRetryCount++;
+      ++this.autoReconnectRetryCount;
       const reconnectDelay = this.getReconnectExponentialDelay()
         ? Utils.exponentialDelay(this.autoReconnectRetryCount)
         : this.getConnectionTimeout() * 1000;