fix: clone configuration only if defined
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index a966037dc2adaac169e025f9adc3d3511356c576..a0dd92ba4641a7dd0709b8ab6d3abb90174cd8c7 100644 (file)
@@ -19,7 +19,12 @@ import { type RawData, WebSocket } from 'ws';
 
 import { AutomaticTransactionGenerator } from './AutomaticTransactionGenerator';
 import { ChargingStationWorkerBroadcastChannel } from './broadcast-channel/ChargingStationWorkerBroadcastChannel';
-import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
+import {
+  addConfigurationKey,
+  deleteConfigurationKey,
+  getConfigurationKey,
+  setConfigurationKeyValue,
+} from './ChargingStationConfigurationUtils';
 import {
   buildConnectorsMap,
   checkConnectorsConfiguration,
@@ -162,7 +167,7 @@ export class ChargingStation {
   public readonly evses: Map<number, EvseStatus>;
   public readonly requests: Map<string, CachedRequest>;
   public performanceStatistics!: PerformanceStatistics | undefined;
-  public heartbeatSetInterval!: NodeJS.Timeout;
+  public heartbeatSetInterval?: NodeJS.Timeout;
   public ocppRequestService!: OCPPRequestService;
   public bootNotificationRequest!: BootNotificationRequest;
   public bootNotificationResponse!: BootNotificationResponse | undefined;
@@ -180,7 +185,7 @@ export class ChargingStation {
   private templateFileWatcher!: FSWatcher | undefined;
   private templateFileHash!: string;
   private readonly sharedLRUCache: SharedLRUCache;
-  private webSocketPingSetInterval!: NodeJS.Timeout;
+  private webSocketPingSetInterval?: NodeJS.Timeout;
   private readonly chargingStationWorkerBroadcastChannel: ChargingStationWorkerBroadcastChannel;
   private reservationExpirationSetInterval?: NodeJS.Timeout;
 
@@ -212,16 +217,8 @@ export class ChargingStation {
       `${
         this.getSupervisionUrlOcppConfiguration() &&
         isNotEmptyString(this.getSupervisionUrlOcppKey()) &&
-        isNotEmptyString(
-          ChargingStationConfigurationUtils.getConfigurationKey(
-            this,
-            this.getSupervisionUrlOcppKey(),
-          )?.value,
-        )
-          ? ChargingStationConfigurationUtils.getConfigurationKey(
-              this,
-              this.getSupervisionUrlOcppKey(),
-            ).value
+        isNotEmptyString(getConfigurationKey(this, this.getSupervisionUrlOcppKey())?.value)
+          ? getConfigurationKey(this, this.getSupervisionUrlOcppKey())!.value
           : this.configuredSupervisionUrl.href
       }/${this.stationInfo.chargingStationId}`,
     );
@@ -232,14 +229,14 @@ export class ChargingStation {
       ` ${
         (isNotEmptyString(this?.stationInfo?.chargingStationId)
           ? this?.stationInfo?.chargingStationId
-          : getChargingStationId(this.index, this.getTemplateFromFile())) ??
+          : getChargingStationId(this.index, this.getTemplateFromFile()!)) ??
         'Error at building log prefix'
       } |`,
     );
   };
 
   public hasIdTags(): boolean {
-    return isNotEmptyArray(this.idTagsCache.getIdTags(getIdTagsFile(this.stationInfo)));
+    return isNotEmptyArray(this.idTagsCache.getIdTags(getIdTagsFile(this.stationInfo)!));
   }
 
   public getEnableStatistics(): boolean {
@@ -250,11 +247,11 @@ export class ChargingStation {
     return this.stationInfo.mustAuthorizeAtRemoteStart ?? true;
   }
 
-  public getNumberOfPhases(stationInfo?: ChargingStationInfo): number | undefined {
+  public getNumberOfPhases(stationInfo?: ChargingStationInfo): number {
     const localStationInfo: ChargingStationInfo = stationInfo ?? this.stationInfo;
     switch (this.getCurrentOutType(stationInfo)) {
       case CurrentType.AC:
-        return !isUndefined(localStationInfo.numberOfPhases) ? localStationInfo.numberOfPhases : 3;
+        return !isUndefined(localStationInfo.numberOfPhases) ? localStationInfo.numberOfPhases! : 3;
       case CurrentType.DC:
         return 0;
     }
@@ -351,7 +348,7 @@ export class ChargingStation {
     return this.stationInfo?.ocppStrictCompliance ?? true;
   }
 
-  public getVoltageOut(stationInfo?: ChargingStationInfo): number | undefined {
+  public getVoltageOut(stationInfo?: ChargingStationInfo): number {
     const defaultVoltageOut = getDefaultVoltageOut(
       this.getCurrentOutType(stationInfo),
       this.logPrefix(),
@@ -362,24 +359,28 @@ export class ChargingStation {
 
   public getMaximumPower(stationInfo?: ChargingStationInfo): number {
     const localStationInfo = stationInfo ?? this.stationInfo;
-    return (localStationInfo['maxPower'] as number) ?? localStationInfo.maximumPower;
+    // eslint-disable-next-line @typescript-eslint/dot-notation
+    return (
+      (localStationInfo['maxPower' as keyof ChargingStationInfo] as number) ??
+      localStationInfo.maximumPower
+    );
   }
 
   public getConnectorMaximumAvailablePower(connectorId: number): number {
-    let connectorAmperageLimitationPowerLimit: number;
+    let connectorAmperageLimitationPowerLimit: number | undefined;
     if (
       !isNullOrUndefined(this.getAmperageLimitation()) &&
-      this.getAmperageLimitation() < this.stationInfo?.maximumAmperage
+      this.getAmperageLimitation()! < this.stationInfo.maximumAmperage!
     ) {
       connectorAmperageLimitationPowerLimit =
         (this.getCurrentOutType() === CurrentType.AC
           ? ACElectricUtils.powerTotal(
               this.getNumberOfPhases(),
               this.getVoltageOut(),
-              this.getAmperageLimitation() *
+              this.getAmperageLimitation()! *
                 (this.hasEvses ? this.getNumberOfEvses() : this.getNumberOfConnectors()),
             )
-          : DCElectricUtils.power(this.getVoltageOut(), this.getAmperageLimitation())) /
+          : DCElectricUtils.power(this.getVoltageOut(), this.getAmperageLimitation()!)) /
         this.powerDivider;
     }
     const connectorMaximumPower = this.getMaximumPower() / this.powerDivider;
@@ -387,10 +388,10 @@ export class ChargingStation {
       getChargingStationConnectorChargingProfilesPowerLimit(this, connectorId);
     return Math.min(
       isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower,
-      isNaN(connectorAmperageLimitationPowerLimit)
+      isNaN(connectorAmperageLimitationPowerLimit!)
         ? Infinity
-        : connectorAmperageLimitationPowerLimit,
-      isNaN(connectorChargingProfilesPowerLimit) ? Infinity : connectorChargingProfilesPowerLimit,
+        : connectorAmperageLimitationPowerLimit!,
+      isNaN(connectorChargingProfilesPowerLimit!) ? Infinity : connectorChargingProfilesPowerLimit!,
     );
   }
 
@@ -486,17 +487,17 @@ export class ChargingStation {
     rounded = false,
   ): number {
     return this.getEnergyActiveImportRegister(
-      this.getConnectorStatus(this.getConnectorIdByTransactionId(transactionId)),
+      this.getConnectorStatus(this.getConnectorIdByTransactionId(transactionId)!)!,
       rounded,
     );
   }
 
   public getEnergyActiveImportRegisterByConnectorId(connectorId: number, rounded = false): number {
-    return this.getEnergyActiveImportRegister(this.getConnectorStatus(connectorId), rounded);
+    return this.getEnergyActiveImportRegister(this.getConnectorStatus(connectorId)!, rounded);
   }
 
   public getAuthorizeRemoteTxRequests(): boolean {
-    const authorizeRemoteTxRequests = ChargingStationConfigurationUtils.getConfigurationKey(
+    const authorizeRemoteTxRequests = getConfigurationKey(
       this,
       StandardParametersKey.AuthorizeRemoteTxRequests,
     );
@@ -504,7 +505,7 @@ export class ChargingStation {
   }
 
   public getLocalAuthListEnabled(): boolean {
-    const localAuthListEnabled = ChargingStationConfigurationUtils.getConfigurationKey(
+    const localAuthListEnabled = getConfigurationKey(
       this,
       StandardParametersKey.LocalAuthListEnabled,
     );
@@ -512,17 +513,11 @@ export class ChargingStation {
   }
 
   public getHeartbeatInterval(): number {
-    const HeartbeatInterval = ChargingStationConfigurationUtils.getConfigurationKey(
-      this,
-      StandardParametersKey.HeartbeatInterval,
-    );
+    const HeartbeatInterval = getConfigurationKey(this, StandardParametersKey.HeartbeatInterval);
     if (HeartbeatInterval) {
       return convertToInt(HeartbeatInterval.value) * 1000;
     }
-    const HeartBeatInterval = ChargingStationConfigurationUtils.getConfigurationKey(
-      this,
-      StandardParametersKey.HeartBeatInterval,
-    );
+    const HeartBeatInterval = getConfigurationKey(this, StandardParametersKey.HeartBeatInterval);
     if (HeartBeatInterval) {
       return convertToInt(HeartBeatInterval.value) * 1000;
     }
@@ -540,11 +535,7 @@ export class ChargingStation {
       this.getSupervisionUrlOcppConfiguration() &&
       isNotEmptyString(this.getSupervisionUrlOcppKey())
     ) {
-      ChargingStationConfigurationUtils.setConfigurationKeyValue(
-        this,
-        this.getSupervisionUrlOcppKey(),
-        url,
-      );
+      setConfigurationKeyValue(this, this.getSupervisionUrlOcppKey(), url);
     } else {
       this.stationInfo.supervisionUrls = url;
       this.saveStationInfo();
@@ -628,12 +619,12 @@ export class ChargingStation {
       return;
     }
     if (interval > 0) {
-      this.getConnectorStatus(connectorId).transactionSetInterval = setInterval(() => {
+      this.getConnectorStatus(connectorId)!.transactionSetInterval = setInterval(() => {
         // FIXME: Implement OCPP version agnostic helpers
         const meterValue: MeterValue = OCPP16ServiceUtils.buildMeterValue(
           this,
           connectorId,
-          this.getConnectorStatus(connectorId).transactionId,
+          this.getConnectorStatus(connectorId)!.transactionId!,
           interval,
         );
         this.ocppRequestService
@@ -696,7 +687,7 @@ export class ChargingStation {
                 this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
                 // Initialize
                 this.initialize();
-                this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo));
+                this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo)!);
                 // Restart the ATG
                 this.stopAutomaticTransactionGenerator();
                 if (this.getAutomaticTransactionGeneratorConfiguration()?.enable === true) {
@@ -755,7 +746,7 @@ export class ChargingStation {
 
   public async reset(reason?: StopTransactionReason): Promise<void> {
     await this.stop(reason);
-    await sleep(this.stationInfo.resetTime);
+    await sleep(this.stationInfo.resetTime!);
     this.initialize();
     this.start();
   }
@@ -767,7 +758,7 @@ export class ChargingStation {
   }
 
   public hasFeatureProfile(featureProfile: SupportedFeatureProfiles): boolean | undefined {
-    return ChargingStationConfigurationUtils.getConfigurationKey(
+    return getConfigurationKey(
       this,
       StandardParametersKey.SupportedFeatureProfiles,
     )?.value?.includes(featureProfile);
@@ -854,9 +845,7 @@ export class ChargingStation {
     }
   }
 
-  public getAutomaticTransactionGeneratorConfiguration():
-    | AutomaticTransactionGeneratorConfiguration
-    | undefined {
+  public getAutomaticTransactionGeneratorConfiguration(): AutomaticTransactionGeneratorConfiguration {
     let automaticTransactionGeneratorConfiguration:
       | AutomaticTransactionGeneratorConfiguration
       | undefined;
@@ -885,7 +874,7 @@ export class ChargingStation {
   public startAutomaticTransactionGenerator(connectorIds?: number[]): void {
     this.automaticTransactionGenerator = AutomaticTransactionGenerator.getInstance(this);
     if (isNotEmptyArray(connectorIds)) {
-      for (const connectorId of connectorIds) {
+      for (const connectorId of connectorIds!) {
         this.automaticTransactionGenerator?.startConnector(connectorId);
       }
     } else {
@@ -897,7 +886,7 @@ export class ChargingStation {
 
   public stopAutomaticTransactionGenerator(connectorIds?: number[]): void {
     if (isNotEmptyArray(connectorIds)) {
-      for (const connectorId of connectorIds) {
+      for (const connectorId of connectorIds!) {
         this.automaticTransactionGenerator?.stopConnector(connectorId);
       }
     } else {
@@ -921,7 +910,7 @@ export class ChargingStation {
       const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
         this,
         connectorId,
-        this.getEnergyActiveImportRegisterByTransactionId(transactionId),
+        this.getEnergyActiveImportRegisterByTransactionId(transactionId!),
       );
       await this.ocppRequestService.requestHandler<MeterValuesRequest, MeterValuesResponse>(
         this,
@@ -938,7 +927,7 @@ export class ChargingStation {
       RequestCommand.STOP_TRANSACTION,
       {
         transactionId,
-        meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId, true),
+        meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId!, true),
         reason,
       },
     );
@@ -946,24 +935,24 @@ export class ChargingStation {
 
   public getReservationOnConnectorId0Enabled(): boolean {
     return convertToBoolean(
-      ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.ReserveConnectorZeroSupported,
-      ).value,
+      getConfigurationKey(this, StandardParametersKey.ReserveConnectorZeroSupported)!.value,
     );
   }
 
   public async addReservation(reservation: Reservation): Promise<void> {
     const [exists, reservationFound] = this.doesReservationExists(reservation);
     if (exists) {
-      await this.removeReservation(reservationFound, ReservationTerminationReason.REPLACE_EXISTING);
+      await this.removeReservation(
+        reservationFound!,
+        ReservationTerminationReason.REPLACE_EXISTING,
+      );
     }
-    this.getConnectorStatus(reservation.connectorId).reservation = reservation;
+    this.getConnectorStatus(reservation.connectorId)!.reservation = reservation;
     await OCPPServiceUtils.sendAndSetConnectorStatus(
       this,
       reservation.connectorId,
       ConnectorStatusEnum.Reserved,
-      null,
+      undefined,
       { send: reservation.connectorId !== 0 },
     );
   }
@@ -972,7 +961,7 @@ export class ChargingStation {
     reservation: Reservation,
     reason?: ReservationTerminationReason,
   ): Promise<void> {
-    const connector = this.getConnectorStatus(reservation.connectorId);
+    const connector = this.getConnectorStatus(reservation.connectorId)!;
     switch (reason) {
       case ReservationTerminationReason.CONNECTOR_STATE_CHANGED:
         delete connector.reservation;
@@ -987,7 +976,7 @@ export class ChargingStation {
           this,
           reservation.connectorId,
           ConnectorStatusEnum.Available,
-          null,
+          undefined,
           { send: reservation.connectorId !== 0 },
         );
         delete connector.reservation;
@@ -1004,26 +993,28 @@ export class ChargingStation {
     if (this.hasEvses) {
       for (const evseStatus of this.evses.values()) {
         for (const connectorStatus of evseStatus.connectors.values()) {
-          if (connectorStatus?.reservation?.[filterKey] === value) {
+          if (connectorStatus?.reservation?.[filterKey as keyof Reservation] === value) {
             return connectorStatus.reservation;
           }
         }
       }
     } else {
       for (const connectorStatus of this.connectors.values()) {
-        if (connectorStatus?.reservation?.[filterKey] === value) {
+        if (connectorStatus?.reservation?.[filterKey as keyof Reservation] === value) {
           return connectorStatus.reservation;
         }
       }
     }
   }
 
-  public doesReservationExists(reservation: Partial<Reservation>): [boolean, Reservation] {
+  public doesReservationExists(
+    reservation: Partial<Reservation>,
+  ): [boolean, Reservation | undefined] {
     const foundReservation = this.getReservationBy(
       ReservationFilterKey.RESERVATION_ID,
-      reservation?.id,
+      reservation.id!,
     );
-    return isUndefined(foundReservation) ? [false, null] : [true, foundReservation];
+    return isUndefined(foundReservation) ? [false, undefined] : [true, foundReservation];
   }
 
   public startReservationExpirationSetInterval(customInterval?: number): void {
@@ -1033,31 +1024,32 @@ export class ChargingStation {
       `${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> => {
-      const now = new Date();
-      if (this.hasEvses) {
-        for (const evseStatus of this.evses.values()) {
-          for (const connectorStatus of evseStatus.connectors.values()) {
-            if (connectorStatus?.reservation?.expiryDate < now) {
-              await this.removeReservation(
+    if (interval > 0) {
+      this.reservationExpirationSetInterval = setInterval((): void => {
+        const now = new Date();
+        if (this.hasEvses) {
+          for (const evseStatus of this.evses.values()) {
+            for (const connectorStatus of evseStatus.connectors.values()) {
+              if (connectorStatus.reservation && connectorStatus.reservation.expiryDate < now) {
+                this.removeReservation(
+                  connectorStatus.reservation,
+                  ReservationTerminationReason.EXPIRED,
+                ).catch(Constants.EMPTY_FUNCTION);
+              }
+            }
+          }
+        } else {
+          for (const connectorStatus of this.connectors.values()) {
+            if (connectorStatus.reservation && connectorStatus.reservation.expiryDate < now) {
+              this.removeReservation(
                 connectorStatus.reservation,
                 ReservationTerminationReason.EXPIRED,
-              );
+              ).catch(Constants.EMPTY_FUNCTION);
             }
           }
         }
-      } else {
-        for (const connectorStatus of this.connectors.values()) {
-          if (connectorStatus?.reservation?.expiryDate < now) {
-            await this.removeReservation(
-              connectorStatus.reservation,
-              ReservationTerminationReason.EXPIRED,
-            );
-          }
-        }
-      }
-    }, interval);
+      }, interval);
+    }
   }
 
   public restartReservationExpiryDateSetInterval(): void {
@@ -1079,11 +1071,11 @@ export class ChargingStation {
       return alreadyExists;
     }
     const userReservedAlready = isUndefined(
-      this.getReservationBy(ReservationFilterKey.ID_TAG, idTag),
+      this.getReservationBy(ReservationFilterKey.ID_TAG, idTag!),
     )
       ? false
       : true;
-    const notConnectorZero = isUndefined(connectorId) ? true : connectorId > 0;
+    const notConnectorZero = isUndefined(connectorId) ? true : connectorId! > 0;
     const freeConnectorsAvailable = this.getNumberOfReservableConnectors() > 0;
     return !alreadyExists && !userReservedAlready && notConnectorZero && freeConnectorsAvailable;
   }
@@ -1113,8 +1105,8 @@ export class ChargingStation {
   private flushMessageBuffer(): void {
     if (this.messageBuffer.size > 0) {
       for (const message of this.messageBuffer.values()) {
-        let beginId: string;
-        let commandName: RequestCommand;
+        let beginId: string | undefined;
+        let commandName: RequestCommand | undefined;
         const [messageType] = JSON.parse(message) as OutgoingRequest | Response | ErrorResponse;
         const isRequest = messageType === MessageType.CALL_MESSAGE;
         if (isRequest) {
@@ -1122,7 +1114,7 @@ export class ChargingStation {
           beginId = PerformanceStatistics.beginMeasure(commandName);
         }
         this.wsConnection?.send(message);
-        isRequest && PerformanceStatistics.endMeasure(commandName, beginId);
+        isRequest && PerformanceStatistics.endMeasure(commandName!, beginId!);
         logger.debug(
           `${this.logPrefix()} >> Buffered ${OCPPServiceUtils.getMessageTypeString(
             messageType,
@@ -1148,7 +1140,7 @@ export class ChargingStation {
   }
 
   private getTemplateFromFile(): ChargingStationTemplate | undefined {
-    let template: ChargingStationTemplate;
+    let template: ChargingStationTemplate | undefined;
     try {
       if (this.sharedLRUCache.hasChargingStationTemplate(this.templateFileHash)) {
         template = this.sharedLRUCache.getChargingStationTemplate(this.templateFileHash);
@@ -1175,7 +1167,7 @@ export class ChargingStation {
   }
 
   private getStationInfoFromTemplate(): ChargingStationInfo {
-    const stationTemplate: ChargingStationTemplate | undefined = this.getTemplateFromFile();
+    const stationTemplate: ChargingStationTemplate = this.getTemplateFromFile()!;
     checkTemplate(stationTemplate, this.logPrefix(), this.templateFile);
     warnTemplateKeysDeprecation(stationTemplate, this.logPrefix(), this.templateFile);
     if (stationTemplate?.Connectors) {
@@ -1204,7 +1196,7 @@ export class ChargingStation {
       stationTemplate?.firmwareVersionPattern ?? Constants.SEMVER_PATTERN;
     if (
       isNotEmptyString(stationInfo.firmwareVersion) &&
-      new RegExp(stationInfo.firmwareVersionPattern).test(stationInfo.firmwareVersion) === false
+      new RegExp(stationInfo.firmwareVersionPattern).test(stationInfo.firmwareVersion!) === false
     ) {
       logger.warn(
         `${this.logPrefix()} Firmware version '${stationInfo.firmwareVersion}' in template file ${
@@ -1222,7 +1214,7 @@ export class ChargingStation {
       stationTemplate?.firmwareUpgrade ?? {},
     );
     stationInfo.resetTime = !isNullOrUndefined(stationTemplate?.resetTime)
-      ? stationTemplate.resetTime * 1000
+      ? stationTemplate.resetTime! * 1000
       : Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
     stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo);
     return stationInfo;
@@ -1246,11 +1238,11 @@ export class ChargingStation {
     // 1. charging station info from template
     // 2. charging station info from configuration file
     if (stationInfoFromFile?.templateHash === stationInfoFromTemplate.templateHash) {
-      return stationInfoFromFile;
+      return stationInfoFromFile!;
     }
     stationInfoFromFile &&
       propagateSerialNumber(
-        this.getTemplateFromFile(),
+        this.getTemplateFromFile()!,
         stationInfoFromFile,
         stationInfoFromTemplate,
       );
@@ -1283,7 +1275,7 @@ export class ChargingStation {
   }
 
   private initialize(): void {
-    const stationTemplate = this.getTemplateFromFile();
+    const stationTemplate = this.getTemplateFromFile()!;
     checkTemplate(stationTemplate, this.logPrefix(), this.templateFile);
     this.configurationFile = join(
       dirname(this.templateFile.replace('station-templates', 'configurations')),
@@ -1292,6 +1284,7 @@ export class ChargingStation {
     const chargingStationConfiguration = this.getConfigurationFromFile();
     if (
       chargingStationConfiguration?.stationInfo?.templateHash === stationTemplate?.templateHash &&
+      // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
       (chargingStationConfiguration?.connectorsStatus || chargingStationConfiguration?.evsesStatus)
     ) {
       this.initializeConnectorsOrEvsesFromFile(chargingStationConfiguration);
@@ -1307,13 +1300,13 @@ export class ChargingStation {
       const patternGroup: number | undefined =
         this.stationInfo.firmwareUpgrade?.versionUpgrade?.patternGroup ??
         this.stationInfo.firmwareVersion?.split('.').length;
-      const match = this.stationInfo?.firmwareVersion
-        ?.match(new RegExp(this.stationInfo.firmwareVersionPattern))
-        ?.slice(1, patternGroup + 1);
+      const match = this.stationInfo
+        .firmwareVersion!.match(new RegExp(this.stationInfo.firmwareVersionPattern!))!
+        .slice(1, patternGroup! + 1);
       const patchLevelIndex = match.length - 1;
       match[patchLevelIndex] = (
         convertToInt(match[patchLevelIndex]) +
-        this.stationInfo.firmwareUpgrade?.versionUpgrade?.step
+        this.stationInfo.firmwareUpgrade!.versionUpgrade!.step!
       ).toString();
       this.stationInfo.firmwareVersion = match?.join('.');
     }
@@ -1322,7 +1315,7 @@ export class ChargingStation {
     if (this.getEnableStatistics() === true) {
       this.performanceStatistics = PerformanceStatistics.getInstance(
         this.stationInfo.hashId,
-        this.stationInfo.chargingStationId,
+        this.stationInfo.chargingStationId!,
         this.configuredSupervisionUrl,
       );
     }
@@ -1366,37 +1359,18 @@ export class ChargingStation {
   }
 
   private initializeOcppConfiguration(): void {
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.HeartbeatInterval,
-      )
-    ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
-        this,
-        StandardParametersKey.HeartbeatInterval,
-        '0',
-      );
+    if (!getConfigurationKey(this, StandardParametersKey.HeartbeatInterval)) {
+      addConfigurationKey(this, StandardParametersKey.HeartbeatInterval, '0');
     }
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.HeartBeatInterval,
-      )
-    ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
-        this,
-        StandardParametersKey.HeartBeatInterval,
-        '0',
-        { visible: false },
-      );
+    if (!getConfigurationKey(this, StandardParametersKey.HeartBeatInterval)) {
+      addConfigurationKey(this, StandardParametersKey.HeartBeatInterval, '0', { visible: false });
     }
     if (
       this.getSupervisionUrlOcppConfiguration() &&
       isNotEmptyString(this.getSupervisionUrlOcppKey()) &&
-      !ChargingStationConfigurationUtils.getConfigurationKey(this, this.getSupervisionUrlOcppKey())
+      !getConfigurationKey(this, this.getSupervisionUrlOcppKey())
     ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
+      addConfigurationKey(
         this,
         this.getSupervisionUrlOcppKey(),
         this.configuredSupervisionUrl.href,
@@ -1405,123 +1379,79 @@ export class ChargingStation {
     } else if (
       !this.getSupervisionUrlOcppConfiguration() &&
       isNotEmptyString(this.getSupervisionUrlOcppKey()) &&
-      ChargingStationConfigurationUtils.getConfigurationKey(this, this.getSupervisionUrlOcppKey())
+      getConfigurationKey(this, this.getSupervisionUrlOcppKey())
     ) {
-      ChargingStationConfigurationUtils.deleteConfigurationKey(
-        this,
-        this.getSupervisionUrlOcppKey(),
-        { save: false },
-      );
+      deleteConfigurationKey(this, this.getSupervisionUrlOcppKey(), { save: false });
     }
     if (
       isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        this.stationInfo.amperageLimitationOcppKey,
-      )
+      !getConfigurationKey(this, this.stationInfo.amperageLimitationOcppKey!)
     ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
+      addConfigurationKey(
         this,
-        this.stationInfo.amperageLimitationOcppKey,
+        this.stationInfo.amperageLimitationOcppKey!,
         (
-          this.stationInfo.maximumAmperage * getAmperageLimitationUnitDivider(this.stationInfo)
+          this.stationInfo.maximumAmperage! * getAmperageLimitationUnitDivider(this.stationInfo)
         ).toString(),
       );
     }
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.SupportedFeatureProfiles,
-      )
-    ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
+    if (!getConfigurationKey(this, StandardParametersKey.SupportedFeatureProfiles)) {
+      addConfigurationKey(
         this,
         StandardParametersKey.SupportedFeatureProfiles,
         `${SupportedFeatureProfiles.Core},${SupportedFeatureProfiles.FirmwareManagement},${SupportedFeatureProfiles.LocalAuthListManagement},${SupportedFeatureProfiles.SmartCharging},${SupportedFeatureProfiles.RemoteTrigger}`,
       );
     }
-    ChargingStationConfigurationUtils.addConfigurationKey(
+    addConfigurationKey(
       this,
       StandardParametersKey.NumberOfConnectors,
       this.getNumberOfConnectors().toString(),
       { readonly: true },
       { overwrite: true },
     );
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.MeterValuesSampledData,
-      )
-    ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
+    if (!getConfigurationKey(this, StandardParametersKey.MeterValuesSampledData)) {
+      addConfigurationKey(
         this,
         StandardParametersKey.MeterValuesSampledData,
         MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
       );
     }
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.ConnectorPhaseRotation,
-      )
-    ) {
+    if (!getConfigurationKey(this, StandardParametersKey.ConnectorPhaseRotation)) {
       const connectorsPhaseRotation: string[] = [];
       if (this.hasEvses) {
         for (const evseStatus of this.evses.values()) {
           for (const connectorId of evseStatus.connectors.keys()) {
             connectorsPhaseRotation.push(
-              getPhaseRotationValue(connectorId, this.getNumberOfPhases()),
+              getPhaseRotationValue(connectorId, this.getNumberOfPhases())!,
             );
           }
         }
       } else {
         for (const connectorId of this.connectors.keys()) {
           connectorsPhaseRotation.push(
-            getPhaseRotationValue(connectorId, this.getNumberOfPhases()),
+            getPhaseRotationValue(connectorId, this.getNumberOfPhases())!,
           );
         }
       }
-      ChargingStationConfigurationUtils.addConfigurationKey(
+      addConfigurationKey(
         this,
         StandardParametersKey.ConnectorPhaseRotation,
         connectorsPhaseRotation.toString(),
       );
     }
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.AuthorizeRemoteTxRequests,
-      )
-    ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
-        this,
-        StandardParametersKey.AuthorizeRemoteTxRequests,
-        'true',
-      );
+    if (!getConfigurationKey(this, StandardParametersKey.AuthorizeRemoteTxRequests)) {
+      addConfigurationKey(this, StandardParametersKey.AuthorizeRemoteTxRequests, 'true');
     }
     if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.LocalAuthListEnabled,
-      ) &&
-      ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.SupportedFeatureProfiles,
-      )?.value?.includes(SupportedFeatureProfiles.LocalAuthListManagement)
-    ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
-        this,
-        StandardParametersKey.LocalAuthListEnabled,
-        'false',
-      );
-    }
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.ConnectionTimeOut,
+      !getConfigurationKey(this, StandardParametersKey.LocalAuthListEnabled) &&
+      getConfigurationKey(this, StandardParametersKey.SupportedFeatureProfiles)?.value?.includes(
+        SupportedFeatureProfiles.LocalAuthListManagement,
       )
     ) {
-      ChargingStationConfigurationUtils.addConfigurationKey(
+      addConfigurationKey(this, StandardParametersKey.LocalAuthListEnabled, 'false');
+    }
+    if (!getConfigurationKey(this, StandardParametersKey.ConnectionTimeOut)) {
+      addConfigurationKey(
         this,
         StandardParametersKey.ConnectionTimeOut,
         Constants.DEFAULT_CONNECTION_TIMEOUT.toString(),
@@ -1542,7 +1472,7 @@ export class ChargingStation {
         this.evses.set(evseId, {
           ...(evseStatus as EvseStatus),
           connectors: new Map<number, ConnectorStatus>(
-            evseStatusConfiguration.connectorsStatus.map((connectorStatus, connectorId) => [
+            evseStatusConfiguration.connectorsStatus!.map((connectorStatus, connectorId) => [
               connectorId,
               connectorStatus,
             ]),
@@ -1582,7 +1512,7 @@ export class ChargingStation {
       logger.error(`${this.logPrefix()} ${errorMsg}`);
       throw new BaseError(errorMsg);
     }
-    if (!stationTemplate?.Connectors[0]) {
+    if (!stationTemplate?.Connectors?.[0]) {
       logger.warn(
         `${this.logPrefix()} Charging station information from template ${
           this.templateFile
@@ -1649,14 +1579,14 @@ export class ChargingStation {
       logger.error(`${this.logPrefix()} ${errorMsg}`);
       throw new BaseError(errorMsg);
     }
-    if (!stationTemplate?.Evses[0]) {
+    if (!stationTemplate?.Evses?.[0]) {
       logger.warn(
         `${this.logPrefix()} Charging station information from template ${
           this.templateFile
         } with no evse id 0 configuration`,
       );
     }
-    if (!stationTemplate?.Evses[0]?.Connectors[0]) {
+    if (!stationTemplate?.Evses?.[0]?.Connectors?.[0]) {
       logger.warn(
         `${this.logPrefix()} Charging station information from template ${
           this.templateFile
@@ -1684,7 +1614,7 @@ export class ChargingStation {
               ),
               availability: AvailabilityType.Operative,
             });
-            initializeConnectorsMapStatus(this.evses.get(evseId)?.connectors, this.logPrefix());
+            initializeConnectorsMapStatus(this.evses.get(evseId)!.connectors, this.logPrefix());
           }
           this.saveEvsesStatus();
         } else {
@@ -1720,7 +1650,7 @@ export class ChargingStation {
           ) as ChargingStationConfiguration;
           PerformanceStatistics.endMeasure(measureId, beginId);
           this.sharedLRUCache.setChargingStationConfiguration(configuration);
-          this.configurationFileHash = configuration.configurationHash;
+          this.configurationFileHash = configuration.configurationHash!;
         }
       } catch (error) {
         handleFileException(
@@ -1754,8 +1684,9 @@ export class ChargingStation {
         if (!existsSync(dirname(this.configurationFile))) {
           mkdirSync(dirname(this.configurationFile), { recursive: true });
         }
-        let configurationData: ChargingStationConfiguration =
-          cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()) ?? {};
+        let configurationData: ChargingStationConfiguration = this.getConfigurationFromFile()
+          ? cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()!)
+          : {};
         if (this.getStationInfoPersistentConfiguration() && this.stationInfo) {
           configurationData.stationInfo = this.stationInfo;
         } else {
@@ -1889,7 +1820,7 @@ export class ChargingStation {
           }
         } while (
           this.isRegistered() === false &&
-          (registrationRetryCount <= this.getRegistrationMaxRetries() ||
+          (registrationRetryCount <= this.getRegistrationMaxRetries()! ||
             this.getRegistrationMaxRetries() === -1)
         );
       }
@@ -1986,7 +1917,7 @@ export class ChargingStation {
     const [responseCallback, , requestCommandName, requestPayload] = this.getCachedRequest(
       messageType,
       messageId,
-    );
+    )!;
     logger.debug(
       `${this.logPrefix()} << Command '${
         requestCommandName ?? Constants.UNKNOWN_COMMAND
@@ -2006,7 +1937,7 @@ export class ChargingStation {
         { errorType, errorMessage, errorDetails },
       );
     }
-    const [, errorCallback, requestCommandName] = this.getCachedRequest(messageType, messageId);
+    const [, errorCallback, requestCommandName] = this.getCachedRequest(messageType, messageId)!;
     logger.debug(
       `${this.logPrefix()} << Command '${
         requestCommandName ?? Constants.UNKNOWN_COMMAND
@@ -2016,10 +1947,11 @@ export class ChargingStation {
   }
 
   private async onMessage(data: RawData): Promise<void> {
-    let request: IncomingRequest | Response | ErrorResponse;
-    let messageType: number;
+    let request: IncomingRequest | Response | ErrorResponse | undefined;
+    let messageType: number | undefined;
     let errorMsg: string;
     try {
+      // eslint-disable-next-line @typescript-eslint/no-base-to-string
       request = JSON.parse(data.toString()) as IncomingRequest | Response | ErrorResponse;
       if (Array.isArray(request) === true) {
         [messageType] = request;
@@ -2046,15 +1978,20 @@ export class ChargingStation {
         }
         parentPort?.postMessage(buildUpdatedMessage(this));
       } else {
-        throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming message is not an array', null, {
-          request,
-        });
+        throw new OCPPError(
+          ErrorType.PROTOCOL_ERROR,
+          'Incoming message is not an array',
+          undefined,
+          {
+            request,
+          },
+        );
       }
     } catch (error) {
-      let commandName: IncomingRequestCommand;
-      let requestCommandName: RequestCommand | IncomingRequestCommand;
+      let commandName: IncomingRequestCommand | undefined;
+      let requestCommandName: RequestCommand | IncomingRequestCommand | undefined;
       let errorCallback: ErrorCallback;
-      const [, messageId] = request;
+      const [, messageId] = request!;
       switch (messageType) {
         case MessageType.CALL_MESSAGE:
           [, , commandName] = request as IncomingRequest;
@@ -2064,7 +2001,7 @@ export class ChargingStation {
         case MessageType.CALL_RESULT_MESSAGE:
         case MessageType.CALL_ERROR_MESSAGE:
           if (this.requests.has(messageId) === true) {
-            [, errorCallback, requestCommandName] = this.getCachedRequest(messageType, messageId);
+            [, errorCallback, requestCommandName] = this.getCachedRequest(messageType, messageId)!;
             // Reject the deferred promise in case of error at response handling (rejecting an already fulfilled promise is a no-op)
             errorCallback(error as OCPPError, false);
           } else {
@@ -2077,6 +2014,7 @@ export class ChargingStation {
         logger.warn(
           `${this.logPrefix()} Error thrown at incoming OCPP command '${
             commandName ?? requestCommandName ?? Constants.UNKNOWN_COMMAND
+            // eslint-disable-next-line @typescript-eslint/no-base-to-string
           }' message '${data.toString()}' handling is not an OCPPError:`,
           error,
         );
@@ -2084,6 +2022,7 @@ export class ChargingStation {
       logger.error(
         `${this.logPrefix()} Incoming OCPP command '${
           commandName ?? requestCommandName ?? Constants.UNKNOWN_COMMAND
+          // eslint-disable-next-line @typescript-eslint/no-base-to-string
         }' message '${data.toString()}'${
           messageType !== MessageType.CALL_MESSAGE
             ? ` matching cached request '${JSON.stringify(this.requests.get(messageId))}'`
@@ -2111,13 +2050,13 @@ export class ChargingStation {
     if (this.getMeteringPerTransaction() === true) {
       return (
         (rounded === true
-          ? Math.round(connectorStatus?.transactionEnergyActiveImportRegisterValue)
+          ? Math.round(connectorStatus.transactionEnergyActiveImportRegisterValue!)
           : connectorStatus?.transactionEnergyActiveImportRegisterValue) ?? 0
       );
     }
     return (
       (rounded === true
-        ? Math.round(connectorStatus?.energyActiveImportRegisterValue)
+        ? Math.round(connectorStatus.energyActiveImportRegisterValue!)
         : connectorStatus?.energyActiveImportRegisterValue) ?? 0
     );
   }
@@ -2149,19 +2088,10 @@ export class ChargingStation {
 
   // 0 for disabling
   private getConnectionTimeout(): number {
-    if (
-      ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.ConnectionTimeOut,
-      )
-    ) {
+    if (getConfigurationKey(this, StandardParametersKey.ConnectionTimeOut)) {
       return (
-        parseInt(
-          ChargingStationConfigurationUtils.getConfigurationKey(
-            this,
-            StandardParametersKey.ConnectionTimeOut,
-          ).value,
-        ) ?? Constants.DEFAULT_CONNECTION_TIMEOUT
+        parseInt(getConfigurationKey(this, StandardParametersKey.ConnectionTimeOut)!.value!) ??
+        Constants.DEFAULT_CONNECTION_TIMEOUT
       );
     }
     return Constants.DEFAULT_CONNECTION_TIMEOUT;
@@ -2204,17 +2134,11 @@ export class ChargingStation {
   private getAmperageLimitation(): number | undefined {
     if (
       isNotEmptyString(this.stationInfo?.amperageLimitationOcppKey) &&
-      ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        this.stationInfo.amperageLimitationOcppKey,
-      )
+      getConfigurationKey(this, this.stationInfo.amperageLimitationOcppKey!)
     ) {
       return (
         convertToInt(
-          ChargingStationConfigurationUtils.getConfigurationKey(
-            this,
-            this.stationInfo.amperageLimitationOcppKey,
-          )?.value,
+          getConfigurationKey(this, this.stationInfo.amperageLimitationOcppKey!)?.value,
         ) / getAmperageLimitationUnitDivider(this.stationInfo)
       );
     }
@@ -2254,7 +2178,7 @@ export class ChargingStation {
           const connectorBootStatus = getBootConnectorStatus(
             this,
             connectorId,
-            this.getConnectorStatus(connectorId),
+            this.getConnectorStatus(connectorId)!,
           );
           await OCPPServiceUtils.sendAndSetConnectorStatus(this, connectorId, connectorBootStatus);
         }
@@ -2333,16 +2257,11 @@ export class ChargingStation {
   }
 
   private startWebSocketPing(): void {
-    const webSocketPingInterval: number = ChargingStationConfigurationUtils.getConfigurationKey(
+    const webSocketPingInterval: number = getConfigurationKey(
       this,
       StandardParametersKey.WebSocketPingInterval,
     )
-      ? convertToInt(
-          ChargingStationConfigurationUtils.getConfigurationKey(
-            this,
-            StandardParametersKey.WebSocketPingInterval,
-          )?.value,
-        )
+      ? convertToInt(getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval)?.value)
       : 0;
     if (webSocketPingInterval > 0 && !this.webSocketPingSetInterval) {
       this.webSocketPingSetInterval = setInterval(() => {
@@ -2382,23 +2301,26 @@ export class ChargingStation {
       let configuredSupervisionUrlIndex: number;
       switch (Configuration.getSupervisionUrlDistribution()) {
         case SupervisionUrlDistribution.RANDOM:
-          configuredSupervisionUrlIndex = Math.floor(secureRandom() * supervisionUrls.length);
+          configuredSupervisionUrlIndex = Math.floor(
+            secureRandom() * (supervisionUrls as string[]).length,
+          );
           break;
         case SupervisionUrlDistribution.ROUND_ROBIN:
         case SupervisionUrlDistribution.CHARGING_STATION_AFFINITY:
         default:
           Object.values(SupervisionUrlDistribution).includes(
-            Configuration.getSupervisionUrlDistribution(),
+            Configuration.getSupervisionUrlDistribution()!,
           ) === false &&
             logger.error(
+              // eslint-disable-next-line @typescript-eslint/no-base-to-string
               `${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' from values '${SupervisionUrlDistribution.toString()}', defaulting to ${
                 SupervisionUrlDistribution.CHARGING_STATION_AFFINITY
               }`,
             );
-          configuredSupervisionUrlIndex = (this.index - 1) % supervisionUrls.length;
+          configuredSupervisionUrlIndex = (this.index - 1) % (supervisionUrls as string[]).length;
           break;
       }
-      configuredSupervisionUrl = supervisionUrls[configuredSupervisionUrlIndex];
+      configuredSupervisionUrl = (supervisionUrls as string[])[configuredSupervisionUrlIndex];
     } else {
       configuredSupervisionUrl = supervisionUrls as string;
     }
@@ -2438,7 +2360,7 @@ export class ChargingStation {
       this.stopAutomaticTransactionGenerator();
     }
     if (
-      this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() ||
+      this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries()! ||
       this.getAutoReconnectMaxRetries() === -1
     ) {
       ++this.autoReconnectRetryCount;