refactor: cleanup reservation check condition
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index bca03a793980ba72304075d3882f7d63e8af4fda..7eef4100355d0113f23848f72bac8c26c9b38acc 100644 (file)
@@ -14,12 +14,18 @@ import { dirname, join } from 'node:path';
 import { URL } from 'node:url';
 import { parentPort } from 'node:worker_threads';
 
+import { millisecondsToSeconds, secondsToMilliseconds } from 'date-fns';
 import merge from 'just-merge';
 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 './ConfigurationKeyUtils';
 import {
   buildConnectorsMap,
   checkConnectorsConfiguration,
@@ -37,11 +43,12 @@ import {
   getIdTagsFile,
   getMaxNumberOfEvses,
   getPhaseRotationValue,
+  hasFeatureProfile,
   initializeConnectorsMapStatus,
   propagateSerialNumber,
   stationTemplateToStationInfo,
   warnTemplateKeysDeprecation,
-} from './ChargingStationUtils';
+} from './Helpers';
 import { IdTagsCache } from './IdTagsCache';
 import {
   OCPP16IncomingRequestService,
@@ -97,7 +104,7 @@ import {
   RegistrationStatusEnumType,
   RequestCommand,
   type Reservation,
-  ReservationFilterKey,
+  type ReservationFilterKey,
   ReservationTerminationReason,
   type Response,
   StandardParametersKey,
@@ -172,6 +179,7 @@ export class ChargingStation {
   private configurationFileHash!: string;
   private connectorsConfigurationHash!: string;
   private evsesConfigurationHash!: string;
+  private automaticTransactionGeneratorConfiguration?: AutomaticTransactionGeneratorConfiguration;
   private ocppIncomingRequestService!: OCPPIncomingRequestService;
   private readonly messageBuffer: Set<string>;
   private configuredSupervisionUrl!: URL;
@@ -212,16 +220,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}`,
     );
@@ -500,7 +500,7 @@ export class ChargingStation {
   }
 
   public getAuthorizeRemoteTxRequests(): boolean {
-    const authorizeRemoteTxRequests = ChargingStationConfigurationUtils.getConfigurationKey(
+    const authorizeRemoteTxRequests = getConfigurationKey(
       this,
       StandardParametersKey.AuthorizeRemoteTxRequests,
     );
@@ -508,7 +508,7 @@ export class ChargingStation {
   }
 
   public getLocalAuthListEnabled(): boolean {
-    const localAuthListEnabled = ChargingStationConfigurationUtils.getConfigurationKey(
+    const localAuthListEnabled = getConfigurationKey(
       this,
       StandardParametersKey.LocalAuthListEnabled,
     );
@@ -516,19 +516,13 @@ 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;
+      return secondsToMilliseconds(convertToInt(HeartbeatInterval.value));
     }
-    const HeartBeatInterval = ChargingStationConfigurationUtils.getConfigurationKey(
-      this,
-      StandardParametersKey.HeartBeatInterval,
-    );
+    const HeartBeatInterval = getConfigurationKey(this, StandardParametersKey.HeartBeatInterval);
     if (HeartBeatInterval) {
-      return convertToInt(HeartBeatInterval.value) * 1000;
+      return secondsToMilliseconds(convertToInt(HeartBeatInterval.value));
     }
     this.stationInfo?.autoRegister === false &&
       logger.warn(
@@ -544,11 +538,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();
@@ -604,14 +594,14 @@ export class ChargingStation {
   public startMeterValues(connectorId: number, interval: number): void {
     if (connectorId === 0) {
       logger.error(
-        `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId.toString()}`,
+        `${this.logPrefix()} Trying to start MeterValues on connector id ${connectorId}`,
       );
       return;
     }
     if (!this.getConnectorStatus(connectorId)) {
       logger.error(
         `${this.logPrefix()} Trying to start MeterValues on non existing connector id
-          ${connectorId.toString()}`,
+          ${connectorId}`,
       );
       return;
     }
@@ -679,7 +669,7 @@ export class ChargingStation {
         if (this.getEnableStatistics() === true) {
           this.performanceStatistics?.start();
         }
-        if (this.hasFeatureProfile(SupportedFeatureProfiles.Reservation)) {
+        if (hasFeatureProfile(this, SupportedFeatureProfiles.Reservation)) {
           this.startReservationExpirationSetInterval();
         }
         this.openWSConnection();
@@ -703,6 +693,7 @@ export class ChargingStation {
                 this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo)!);
                 // Restart the ATG
                 this.stopAutomaticTransactionGenerator();
+                delete this.automaticTransactionGeneratorConfiguration;
                 if (this.getAutomaticTransactionGeneratorConfiguration()?.enable === true) {
                   this.startAutomaticTransactionGenerator();
                 }
@@ -741,6 +732,9 @@ export class ChargingStation {
         if (this.getEnableStatistics() === true) {
           this.performanceStatistics?.stop();
         }
+        if (hasFeatureProfile(this, SupportedFeatureProfiles.Reservation)) {
+          this.stopReservationExpirationSetInterval();
+        }
         this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
         this.templateFileWatcher?.close();
         this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
@@ -770,13 +764,6 @@ export class ChargingStation {
     }
   }
 
-  public hasFeatureProfile(featureProfile: SupportedFeatureProfiles): boolean | undefined {
-    return ChargingStationConfigurationUtils.getConfigurationKey(
-      this,
-      StandardParametersKey.SupportedFeatureProfiles,
-    )?.value?.includes(featureProfile);
-  }
-
   public bufferMessage(message: string): void {
     this.messageBuffer.add(message);
   }
@@ -788,7 +775,7 @@ export class ChargingStation {
       terminateOpened: false,
     },
   ): void {
-    options = { handshakeTimeout: this.getConnectionTimeout() * 1000, ...options };
+    options = { handshakeTimeout: secondsToMilliseconds(this.getConnectionTimeout()), ...options };
     params = { ...{ closeOpened: false, terminateOpened: false }, ...params };
     if (this.started === false && this.starting === false) {
       logger.warn(
@@ -859,25 +846,28 @@ export class ChargingStation {
   }
 
   public getAutomaticTransactionGeneratorConfiguration(): AutomaticTransactionGeneratorConfiguration {
-    let automaticTransactionGeneratorConfiguration:
-      | AutomaticTransactionGeneratorConfiguration
-      | undefined;
-    const automaticTransactionGeneratorConfigurationFromFile =
-      this.getConfigurationFromFile()?.automaticTransactionGenerator;
-    if (
-      this.getAutomaticTransactionGeneratorPersistentConfiguration() &&
-      automaticTransactionGeneratorConfigurationFromFile
-    ) {
-      automaticTransactionGeneratorConfiguration =
-        automaticTransactionGeneratorConfigurationFromFile;
-    } else {
-      automaticTransactionGeneratorConfiguration =
-        this.getTemplateFromFile()?.AutomaticTransactionGenerator;
+    if (isNullOrUndefined(this.automaticTransactionGeneratorConfiguration)) {
+      let automaticTransactionGeneratorConfiguration:
+        | AutomaticTransactionGeneratorConfiguration
+        | undefined;
+      const automaticTransactionGeneratorConfigurationFromFile =
+        this.getConfigurationFromFile()?.automaticTransactionGenerator;
+      if (
+        this.getAutomaticTransactionGeneratorPersistentConfiguration() &&
+        automaticTransactionGeneratorConfigurationFromFile
+      ) {
+        automaticTransactionGeneratorConfiguration =
+          automaticTransactionGeneratorConfigurationFromFile;
+      } else {
+        automaticTransactionGeneratorConfiguration =
+          this.getTemplateFromFile()?.AutomaticTransactionGenerator;
+      }
+      this.automaticTransactionGeneratorConfiguration = {
+        ...Constants.DEFAULT_ATG_CONFIGURATION,
+        ...automaticTransactionGeneratorConfiguration,
+      };
     }
-    return {
-      ...Constants.DEFAULT_ATG_CONFIGURATION,
-      ...automaticTransactionGeneratorConfiguration,
-    };
+    return this.automaticTransactionGeneratorConfiguration!;
   }
 
   public getAutomaticTransactionGeneratorStatuses(): Status[] | undefined {
@@ -946,18 +936,15 @@ export class ChargingStation {
     );
   }
 
-  public getReservationOnConnectorId0Enabled(): boolean {
+  public getReserveConnectorZeroSupported(): 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) {
+    const reservationFound = this.getReservationBy('reservationId', reservation.reservationId);
+    if (!isUndefined(reservationFound)) {
       await this.removeReservation(
         reservationFound!,
         ReservationTerminationReason.REPLACE_EXISTING,
@@ -980,8 +967,6 @@ export class ChargingStation {
     const connector = this.getConnectorStatus(reservation.connectorId)!;
     switch (reason) {
       case ReservationTerminationReason.CONNECTOR_STATE_CHANGED:
-        delete connector.reservation;
-        break;
       case ReservationTerminationReason.TRANSACTION_STARTED:
         delete connector.reservation;
         break;
@@ -1009,59 +994,55 @@ export class ChargingStation {
     if (this.hasEvses) {
       for (const evseStatus of this.evses.values()) {
         for (const connectorStatus of evseStatus.connectors.values()) {
-          if (connectorStatus?.reservation?.[filterKey as keyof Reservation] === value) {
+          if (connectorStatus?.reservation?.[filterKey] === value) {
             return connectorStatus.reservation;
           }
         }
       }
     } else {
       for (const connectorStatus of this.connectors.values()) {
-        if (connectorStatus?.reservation?.[filterKey as keyof Reservation] === value) {
+        if (connectorStatus?.reservation?.[filterKey] === value) {
           return connectorStatus.reservation;
         }
       }
     }
   }
 
-  public doesReservationExists(
-    reservation: Partial<Reservation>,
-  ): [boolean, Reservation | undefined] {
-    const foundReservation = this.getReservationBy(
-      ReservationFilterKey.RESERVATION_ID,
-      reservation.id!,
-    );
-    return isUndefined(foundReservation) ? [false, undefined] : [true, foundReservation];
-  }
-
   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`,
-    );
     if (interval > 0) {
-      // eslint-disable-next-line @typescript-eslint/no-misused-promises
-      this.reservationExpirationSetInterval = setInterval(async (): Promise<void> => {
-        const now = new Date();
+      logger.info(
+        `${this.logPrefix()} Reservation expiration date checks started every ${formatDurationMilliSeconds(
+          interval,
+        )}`,
+      );
+      this.reservationExpirationSetInterval = setInterval((): void => {
+        const currentDate = 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(
-                  connectorStatus.reservation!,
+              if (
+                connectorStatus.reservation &&
+                connectorStatus.reservation.expiryDate < currentDate
+              ) {
+                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!,
+            if (
+              connectorStatus.reservation &&
+              connectorStatus.reservation.expiryDate < currentDate
+            ) {
+              this.removeReservation(
+                connectorStatus.reservation,
                 ReservationTerminationReason.EXPIRED,
-              );
+              ).catch(Constants.EMPTY_FUNCTION);
             }
           }
         }
@@ -1074,27 +1055,24 @@ export class ChargingStation {
     this.startReservationExpirationSetInterval();
   }
 
-  public validateIncomingRequestWithReservation(connectorId: number, idTag: string): boolean {
-    return this.getReservationBy(ReservationFilterKey.CONNECTOR_ID, connectorId)?.idTag === idTag;
-  }
-
   public isConnectorReservable(
     reservationId: number,
     idTag?: string,
     connectorId?: number,
   ): boolean {
-    const [alreadyExists] = this.doesReservationExists({ id: reservationId });
-    if (alreadyExists) {
-      return alreadyExists;
+    const reservationExists = !isUndefined(this.getReservationBy('reservationId', reservationId));
+    if (arguments.length === 1) {
+      return !reservationExists;
+    } else if (arguments.length > 1) {
+      const userReservationExists =
+        !isUndefined(idTag) && isUndefined(this.getReservationBy('idTag', idTag!)) ? false : true;
+      const notConnectorZero = isUndefined(connectorId) ? true : connectorId! > 0;
+      const freeConnectorsAvailable = this.getNumberOfReservableConnectors() > 0;
+      return (
+        !reservationExists && !userReservationExists && notConnectorZero && freeConnectorsAvailable
+      );
     }
-    const userReservedAlready = isUndefined(
-      this.getReservationBy(ReservationFilterKey.ID_TAG, idTag!),
-    )
-      ? false
-      : true;
-    const notConnectorZero = isUndefined(connectorId) ? true : connectorId! > 0;
-    const freeConnectorsAvailable = this.getNumberOfReservableConnectors() > 0;
-    return !alreadyExists && !userReservedAlready && notConnectorZero && freeConnectorsAvailable;
+    return false;
   }
 
   private getNumberOfReservableConnectors(): number {
@@ -1111,9 +1089,11 @@ export class ChargingStation {
 
   private getNumberOfReservationsOnConnectorZero(): number {
     let numberOfReservations = 0;
-    if (this.hasEvses && this.evses.get(0)?.connectors.get(0)?.reservation) {
-      ++numberOfReservations;
-    } else if (this.connectors.get(0)?.reservation) {
+    if (
+      // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+      (this.hasEvses && this.evses.get(0)?.connectors.get(0)?.reservation) ||
+      (!this.hasEvses && this.connectors.get(0)?.reservation)
+    ) {
       ++numberOfReservations;
     }
     return numberOfReservations;
@@ -1231,7 +1211,7 @@ export class ChargingStation {
       stationTemplate?.firmwareUpgrade ?? {},
     );
     stationInfo.resetTime = !isNullOrUndefined(stationTemplate?.resetTime)
-      ? stationTemplate.resetTime! * 1000
+      ? secondsToMilliseconds(stationTemplate.resetTime!)
       : Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
     stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo);
     return stationInfo;
@@ -1345,7 +1325,7 @@ export class ChargingStation {
     if (this.stationInfo?.autoRegister === true) {
       this.bootNotificationResponse = {
         currentTime: new Date(),
-        interval: this.getHeartbeatInterval() / 1000,
+        interval: millisecondsToSeconds(this.getHeartbeatInterval()),
         status: RegistrationStatusEnumType.ACCEPTED,
       };
     }
@@ -1376,37 +1356,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,
@@ -1415,22 +1376,15 @@ 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!,
         (
@@ -1438,43 +1392,28 @@ export class ChargingStation {
         ).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()) {
@@ -1491,47 +1430,25 @@ export class ChargingStation {
           );
         }
       }
-      ChargingStationConfigurationUtils.addConfigurationKey(
+      addConfigurationKey(
         this,
         StandardParametersKey.ConnectorPhaseRotation,
         connectorsPhaseRotation.toString(),
       );
     }
-    if (
-      !ChargingStationConfigurationUtils.getConfigurationKey(
-        this,
-        StandardParametersKey.AuthorizeRemoteTxRequests,
-      )
-    ) {
-      ChargingStationConfigurationUtils.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 (!getConfigurationKey(this, StandardParametersKey.AuthorizeRemoteTxRequests)) {
+      addConfigurationKey(this, StandardParametersKey.AuthorizeRemoteTxRequests, 'true');
     }
     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(),
@@ -1764,8 +1681,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 {
@@ -1893,7 +1811,7 @@ export class ChargingStation {
             this.getRegistrationMaxRetries() !== -1 && ++registrationRetryCount;
             await sleep(
               this?.bootNotificationResponse?.interval
-                ? this.bootNotificationResponse.interval * 1000
+                ? secondsToMilliseconds(this.bootNotificationResponse.interval)
                 : Constants.DEFAULT_BOOT_NOTIFICATION_INTERVAL,
             );
           }
@@ -2167,19 +2085,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;
@@ -2222,17 +2131,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)
       );
     }
@@ -2351,23 +2254,18 @@ 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(() => {
         if (this.isWebSocketConnectionOpened() === true) {
           this.wsConnection?.ping();
         }
-      }, webSocketPingInterval * 1000);
+      }, secondsToMilliseconds(webSocketPingInterval));
       logger.info(
         `${this.logPrefix()} WebSocket ping started every ${formatDurationSeconds(
           webSocketPingInterval,
@@ -2465,7 +2363,7 @@ export class ChargingStation {
       ++this.autoReconnectRetryCount;
       const reconnectDelay = this.getReconnectExponentialDelay()
         ? exponentialDelay(this.autoReconnectRetryCount)
-        : this.getConnectionTimeout() * 1000;
+        : secondsToMilliseconds(this.getConnectionTimeout());
       const reconnectDelayWithdraw = 1000;
       const reconnectTimeout =
         reconnectDelay && reconnectDelay - reconnectDelayWithdraw > 0