refactor: factor out default OCPP request params value
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 419e89e36a8f768952e9c15976d2f28fdce09900..54af77fc0351bb3d918536c046ecab95c080594b 100644 (file)
@@ -9,31 +9,24 @@ import { parentPort } from 'node:worker_threads';
 import merge from 'just-merge';
 import WebSocket, { type RawData } from 'ws';
 
+import { AutomaticTransactionGenerator } from './AutomaticTransactionGenerator';
+import { ChargingStationWorkerBroadcastChannel } from './broadcast-channel/ChargingStationWorkerBroadcastChannel';
+import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
+import { ChargingStationUtils } from './ChargingStationUtils';
+import { IdTagsCache } from './IdTagsCache';
 import {
-  AutomaticTransactionGenerator,
-  ChargingStationConfigurationUtils,
-  ChargingStationUtils,
-  ChargingStationWorkerBroadcastChannel,
-  IdTagsCache,
-  MessageChannelUtils,
-  SharedLRUCache,
-} from './internal';
-import {
-  // OCPP16IncomingRequestService,
+  OCPP16IncomingRequestService,
   OCPP16RequestService,
-  // OCPP16ResponseService,
+  OCPP16ResponseService,
   OCPP16ServiceUtils,
   OCPP20IncomingRequestService,
   OCPP20RequestService,
-  // OCPP20ResponseService,
+  OCPP20ResponseService,
   type OCPPIncomingRequestService,
   type OCPPRequestService,
-  // OCPPServiceUtils,
+  OCPPServiceUtils,
 } from './ocpp';
-import { OCPP16IncomingRequestService } from './ocpp/1.6/OCPP16IncomingRequestService';
-import { OCPP16ResponseService } from './ocpp/1.6/OCPP16ResponseService';
-import { OCPP20ResponseService } from './ocpp/2.0/OCPP20ResponseService';
-import { OCPPServiceUtils } from './ocpp/OCPPServiceUtils';
+import { SharedLRUCache } from './SharedLRUCache';
 import { BaseError, OCPPError } from '../exception';
 import { PerformanceStatistics } from '../performance';
 import {
@@ -90,11 +83,18 @@ import {
 } from '../types';
 import {
   ACElectricUtils,
+  AsyncLock,
+  AsyncLockType,
   Configuration,
   Constants,
   DCElectricUtils,
+  ErrorUtils,
   FileUtils,
+  MessageChannelUtils,
   Utils,
+  buildChargingStationAutomaticTransactionGeneratorConfiguration,
+  buildConnectorsStatus,
+  buildEvsesStatus,
   logger,
 } from '../utils';
 
@@ -160,11 +160,17 @@ export class ChargingStation {
     return new URL(
       `${
         this.getSupervisionUrlOcppConfiguration() &&
-        Utils.isNotEmptyString(this.getSupervisionUrlOcppKey())
+        Utils.isNotEmptyString(this.getSupervisionUrlOcppKey()) &&
+        Utils.isNotEmptyString(
+          ChargingStationConfigurationUtils.getConfigurationKey(
+            this,
+            this.getSupervisionUrlOcppKey()
+          )?.value
+        )
           ? ChargingStationConfigurationUtils.getConfigurationKey(
               this,
               this.getSupervisionUrlOcppKey()
-            )?.value
+            ).value
           : this.configuredSupervisionUrl.href
       }/${this.stationInfo.chargingStationId}`
     );
@@ -182,8 +188,9 @@ export class ChargingStation {
   };
 
   public hasIdTags(): boolean {
-    const idTagsFile = ChargingStationUtils.getIdTagsFile(this.stationInfo);
-    return Utils.isNotEmptyArray(this.idTagsCache.getIdTags(idTagsFile));
+    return Utils.isNotEmptyArray(
+      this.idTagsCache.getIdTags(ChargingStationUtils.getIdTagsFile(this.stationInfo))
+    );
   }
 
   public getEnableStatistics(): boolean {
@@ -218,26 +225,26 @@ export class ChargingStation {
     return this?.bootNotificationResponse?.status;
   }
 
-  public isInUnknownState(): boolean {
+  public inUnknownState(): boolean {
     return Utils.isNullOrUndefined(this?.bootNotificationResponse?.status);
   }
 
-  public isInPendingState(): boolean {
+  public inPendingState(): boolean {
     return this?.bootNotificationResponse?.status === RegistrationStatusEnumType.PENDING;
   }
 
-  public isInAcceptedState(): boolean {
+  public inAcceptedState(): boolean {
     return this?.bootNotificationResponse?.status === RegistrationStatusEnumType.ACCEPTED;
   }
 
-  public isInRejectedState(): boolean {
+  public inRejectedState(): boolean {
     return this?.bootNotificationResponse?.status === RegistrationStatusEnumType.REJECTED;
   }
 
   public isRegistered(): boolean {
     return (
-      this.isInUnknownState() === false &&
-      (this.isInAcceptedState() === true || this.isInPendingState() === true)
+      this.inUnknownState() === false &&
+      (this.inAcceptedState() === true || this.inPendingState() === true)
     );
   }
 
@@ -313,13 +320,10 @@ export class ChargingStation {
   public getVoltageOut(stationInfo?: ChargingStationInfo): number | undefined {
     const defaultVoltageOut = ChargingStationUtils.getDefaultVoltageOut(
       this.getCurrentOutType(stationInfo),
-      this.templateFile,
-      this.logPrefix()
+      this.logPrefix(),
+      this.templateFile
     );
-    const localStationInfo: ChargingStationInfo = stationInfo ?? this.stationInfo;
-    return !Utils.isUndefined(localStationInfo.voltageOut)
-      ? localStationInfo.voltageOut
-      : defaultVoltageOut;
+    return (stationInfo ?? this.stationInfo).voltageOut ?? defaultVoltageOut;
   }
 
   public getMaximumPower(stationInfo?: ChargingStationInfo): number {
@@ -658,9 +662,7 @@ export class ChargingStation {
                 this.initialize();
                 // Restart the ATG
                 this.stopAutomaticTransactionGenerator();
-                if (
-                  this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true
-                ) {
+                if (this.getAutomaticTransactionGeneratorConfiguration()?.enable === true) {
                   this.startAutomaticTransactionGenerator();
                 }
                 if (this.getEnableStatistics() === true) {
@@ -703,6 +705,7 @@ export class ChargingStation {
         this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
         delete this.bootNotificationResponse;
         this.started = false;
+        this.saveConfiguration();
         parentPort?.postMessage(MessageChannelUtils.buildStoppedMessage(this));
         this.stopping = false;
       } else {
@@ -812,15 +815,29 @@ export class ChargingStation {
     }
   }
 
-  public startAutomaticTransactionGenerator(
-    connectorIds?: number[],
-    automaticTransactionGeneratorConfiguration?: AutomaticTransactionGeneratorConfiguration
-  ): void {
-    this.automaticTransactionGenerator = AutomaticTransactionGenerator.getInstance(
-      automaticTransactionGeneratorConfiguration ??
-        this.getAutomaticTransactionGeneratorConfigurationFromTemplate(),
-      this
-    );
+  public getAutomaticTransactionGeneratorConfiguration():
+    | AutomaticTransactionGeneratorConfiguration
+    | undefined {
+    let automaticTransactionGeneratorConfiguration:
+      | AutomaticTransactionGeneratorConfiguration
+      | undefined;
+    const automaticTransactionGeneratorConfigurationFromFile =
+      this.getConfigurationFromFile()?.automaticTransactionGenerator;
+    if (automaticTransactionGeneratorConfigurationFromFile) {
+      automaticTransactionGeneratorConfiguration =
+        automaticTransactionGeneratorConfigurationFromFile;
+    } else {
+      automaticTransactionGeneratorConfiguration =
+        this.getTemplateFromFile()?.AutomaticTransactionGenerator;
+    }
+    return {
+      ...Constants.DEFAULT_ATG_CONFIGURATION,
+      ...automaticTransactionGeneratorConfiguration,
+    };
+  }
+
+  public startAutomaticTransactionGenerator(connectorIds?: number[]): void {
+    this.automaticTransactionGenerator = AutomaticTransactionGenerator.getInstance(this);
     if (Utils.isNotEmptyArray(connectorIds)) {
       for (const connectorId of connectorIds) {
         this.automaticTransactionGenerator?.startConnector(connectorId);
@@ -828,6 +845,7 @@ export class ChargingStation {
     } else {
       this.automaticTransactionGenerator?.start();
     }
+    this.saveChargingStationAutomaticTransactionGeneratorConfiguration();
     parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
   }
 
@@ -839,6 +857,7 @@ export class ChargingStation {
     } else {
       this.automaticTransactionGenerator?.stop();
     }
+    this.saveChargingStationAutomaticTransactionGeneratorConfiguration();
     parentPort?.postMessage(MessageChannelUtils.buildUpdatedMessage(this));
   }
 
@@ -930,7 +949,7 @@ export class ChargingStation {
         this.templateFileHash = template.templateHash;
       }
     } catch (error) {
-      FileUtils.handleFileException(
+      ErrorUtils.handleFileException(
         this.templateFile,
         FileType.ChargingStationTemplate,
         error as NodeJS.ErrnoException,
@@ -942,21 +961,19 @@ export class ChargingStation {
 
   private getStationInfoFromTemplate(): ChargingStationInfo {
     const stationTemplate: ChargingStationTemplate | undefined = this.getTemplateFromFile();
-    if (Utils.isNullOrUndefined(stationTemplate)) {
-      const errorMsg = `Failed to read charging station template file ${this.templateFile}`;
-      logger.error(`${this.logPrefix()} ${errorMsg}`);
-      throw new BaseError(errorMsg);
-    }
-    if (Utils.isEmptyObject(stationTemplate)) {
-      const errorMsg = `Empty charging station information from template file ${this.templateFile}`;
-      logger.error(`${this.logPrefix()} ${errorMsg}`);
-      throw new BaseError(errorMsg);
-    }
+    ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile);
     ChargingStationUtils.warnTemplateKeysDeprecation(
-      this.templateFile,
       stationTemplate,
-      this.logPrefix()
+      this.logPrefix(),
+      this.templateFile
     );
+    if (stationTemplate?.Connectors) {
+      ChargingStationUtils.checkConnectorsConfiguration(
+        stationTemplate,
+        this.logPrefix(),
+        this.templateFile
+      );
+    }
     const stationInfo: ChargingStationInfo =
       ChargingStationUtils.stationTemplateToStationInfo(stationTemplate);
     stationInfo.hashId = ChargingStationUtils.getHashId(this.index, stationTemplate);
@@ -1005,15 +1022,6 @@ export class ChargingStation {
       ? stationTemplate.resetTime * 1000
       : Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
     stationInfo.maximumAmperage = this.getMaximumAmperage(stationInfo);
-    if (stationInfo?.Connectors) {
-      ChargingStationUtils.checkConnectorsConfiguration(
-        stationInfo,
-        this.templateFile,
-        this.logPrefix()
-      );
-    }
-    delete stationInfo?.Connectors;
-    delete stationInfo?.Evses;
     return stationInfo;
   }
 
@@ -1068,16 +1076,21 @@ export class ChargingStation {
 
   private initialize(): void {
     const stationTemplate = this.getTemplateFromFile();
-    if (Utils.isNullOrUndefined(stationTemplate)) {
-      const errorMsg = `Failed to read charging station template file ${this.templateFile}`;
-      logger.error(`${this.logPrefix()} ${errorMsg}`);
-      throw new BaseError(errorMsg);
-    }
+    ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile);
     this.configurationFile = path.join(
       path.dirname(this.templateFile.replace('station-templates', 'configurations')),
       `${ChargingStationUtils.getHashId(this.index, stationTemplate)}.json`
     );
-    this.initializeConnectorsOrEvses(stationTemplate);
+    const chargingStationConfiguration = this.getConfigurationFromFile();
+    const featureFlag = false;
+    if (
+      featureFlag &&
+      (chargingStationConfiguration?.connectorsStatus || chargingStationConfiguration?.evsesStatus)
+    ) {
+      this.initializeConnectorsOrEvsesFromFile(chargingStationConfiguration);
+    } else {
+      this.initializeConnectorsOrEvsesFromTemplate(stationTemplate);
+    }
     this.stationInfo = this.getStationInfo();
     if (
       this.stationInfo.firmwareStatus === FirmwareStatus.Installing &&
@@ -1313,11 +1326,41 @@ export class ChargingStation {
     this.saveOcppConfiguration();
   }
 
-  private initializeConnectorsOrEvses(stationTemplate: ChargingStationTemplate) {
+  private initializeConnectorsOrEvsesFromFile(configuration: ChargingStationConfiguration): void {
+    if (configuration?.connectorsStatus && !configuration?.evsesStatus) {
+      for (const [connectorId, connectorStatus] of configuration.connectorsStatus.entries()) {
+        this.connectors.set(connectorId, Utils.cloneObject<ConnectorStatus>(connectorStatus));
+      }
+    } else if (configuration?.evsesStatus && !configuration?.connectorsStatus) {
+      for (const [evseId, evseStatusConfiguration] of configuration.evsesStatus.entries()) {
+        const evseStatus = Utils.cloneObject<EvseStatusConfiguration>(evseStatusConfiguration);
+        delete evseStatus.connectorsStatus;
+        this.evses.set(evseId, {
+          ...(evseStatus as EvseStatus),
+          connectors: new Map<number, ConnectorStatus>(
+            evseStatusConfiguration.connectorsStatus.map((connectorStatus, connectorId) => [
+              connectorId,
+              connectorStatus,
+            ])
+          ),
+        });
+      }
+    } else if (configuration?.evsesStatus && configuration?.connectorsStatus) {
+      const errorMsg = `Connectors and evses defined at the same time in configuration file ${this.configurationFile}`;
+      logger.error(`${this.logPrefix()} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    } else {
+      const errorMsg = `No connectors or evses defined in configuration file ${this.configurationFile}`;
+      logger.error(`${this.logPrefix()} ${errorMsg}`);
+      throw new BaseError(errorMsg);
+    }
+  }
+
+  private initializeConnectorsOrEvsesFromTemplate(stationTemplate: ChargingStationTemplate) {
     if (stationTemplate?.Connectors && !stationTemplate?.Evses) {
-      this.initializeConnectors(stationTemplate);
+      this.initializeConnectorsFromTemplate(stationTemplate);
     } else if (stationTemplate?.Evses && !stationTemplate?.Connectors) {
-      this.initializeEvses(stationTemplate);
+      this.initializeEvsesFromTemplate(stationTemplate);
     } else if (stationTemplate?.Evses && stationTemplate?.Connectors) {
       const errorMsg = `Connectors and evses defined at the same time in template file ${this.templateFile}`;
       logger.error(`${this.logPrefix()} ${errorMsg}`);
@@ -1329,7 +1372,7 @@ export class ChargingStation {
     }
   }
 
-  private initializeConnectors(stationTemplate: ChargingStationTemplate): void {
+  private initializeConnectorsFromTemplate(stationTemplate: ChargingStationTemplate): void {
     if (!stationTemplate?.Connectors && this.connectors.size === 0) {
       const errorMsg = `No already defined connectors and charging station information from template ${this.templateFile} with no connectors configuration defined`;
       logger.error(`${this.logPrefix()} ${errorMsg}`);
@@ -1346,8 +1389,8 @@ export class ChargingStation {
       const { configuredMaxConnectors, templateMaxConnectors, templateMaxAvailableConnectors } =
         ChargingStationUtils.checkConnectorsConfiguration(
           stationTemplate,
-          this.templateFile,
-          this.logPrefix()
+          this.logPrefix(),
+          this.templateFile
         );
       const connectorsConfigHash = crypto
         .createHash(Constants.DEFAULT_HASH_ALGORITHM)
@@ -1401,7 +1444,7 @@ export class ChargingStation {
     }
   }
 
-  private initializeEvses(stationTemplate: ChargingStationTemplate): void {
+  private initializeEvsesFromTemplate(stationTemplate: ChargingStationTemplate): void {
     if (!stationTemplate?.Evses && this.evses.size === 0) {
       const errorMsg = `No already defined evses and charging station information from template ${this.templateFile} with no evses configuration defined`;
       logger.error(`${this.logPrefix()} ${errorMsg}`);
@@ -1468,7 +1511,7 @@ export class ChargingStation {
 
   private getConfigurationFromFile(): ChargingStationConfiguration | undefined {
     let configuration: ChargingStationConfiguration | undefined;
-    if (this.configurationFile && fs.existsSync(this.configurationFile)) {
+    if (Utils.isNotEmptyString(this.configurationFile) && fs.existsSync(this.configurationFile)) {
       try {
         if (this.sharedLRUCache.hasChargingStationConfiguration(this.configurationFileHash)) {
           configuration = this.sharedLRUCache.getChargingStationConfiguration(
@@ -1485,7 +1528,7 @@ export class ChargingStation {
           this.configurationFileHash = configuration.configurationHash;
         }
       } catch (error) {
-        FileUtils.handleFileException(
+        ErrorUtils.handleFileException(
           this.configurationFile,
           FileType.ChargingStationConfiguration,
           error as NodeJS.ErrnoException,
@@ -1496,50 +1539,41 @@ export class ChargingStation {
     return configuration;
   }
 
+  private saveChargingStationAutomaticTransactionGeneratorConfiguration(): void {
+    this.saveConfiguration();
+  }
+
   private saveConnectorsStatus() {
-    if (this.getOcppPersistentConfiguration()) {
-      this.saveConfiguration();
-    }
+    this.saveConfiguration();
   }
 
   private saveEvsesStatus() {
-    if (this.getOcppPersistentConfiguration()) {
-      this.saveConfiguration();
-    }
+    this.saveConfiguration();
   }
 
   private saveConfiguration(): void {
-    if (this.configurationFile) {
+    if (Utils.isNotEmptyString(this.configurationFile)) {
       try {
         if (!fs.existsSync(path.dirname(this.configurationFile))) {
           fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
         }
-        const configurationData: ChargingStationConfiguration =
-          Utils.cloneObject(this.getConfigurationFromFile()) ?? {};
-        if (this.stationInfo) {
+        let configurationData: ChargingStationConfiguration =
+          Utils.cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()) ?? {};
+        if (this.getStationInfoPersistentConfiguration() && this.stationInfo) {
           configurationData.stationInfo = this.stationInfo;
         }
-        if (this.ocppConfiguration?.configurationKey) {
+        if (this.getOcppPersistentConfiguration() && this.ocppConfiguration?.configurationKey) {
           configurationData.configurationKey = this.ocppConfiguration.configurationKey;
         }
+        configurationData = merge<ChargingStationConfiguration>(
+          configurationData,
+          buildChargingStationAutomaticTransactionGeneratorConfiguration(this)
+        );
         if (this.connectors.size > 0) {
-          configurationData.connectorsStatus = [...this.connectors.values()].map(
-            // eslint-disable-next-line @typescript-eslint/no-unused-vars
-            ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest
-          );
+          configurationData.connectorsStatus = buildConnectorsStatus(this);
         }
         if (this.evses.size > 0) {
-          configurationData.evsesStatus = [...this.evses.values()].map((evseStatus) => {
-            const status = {
-              ...evseStatus,
-              connectorsStatus: [...evseStatus.connectors.values()].map(
-                // eslint-disable-next-line @typescript-eslint/no-unused-vars
-                ({ transactionSetInterval, ...connectorStatusRest }) => connectorStatusRest
-              ),
-            };
-            delete status.connectors;
-            return status as EvseStatusConfiguration;
-          });
+          configurationData.evsesStatus = buildEvsesStatus(this);
         }
         delete configurationData.configurationHash;
         const configurationHash = crypto
@@ -1547,16 +1581,30 @@ export class ChargingStation {
           .update(JSON.stringify(configurationData))
           .digest('hex');
         if (this.configurationFileHash !== configurationHash) {
-          configurationData.configurationHash = configurationHash;
-          const measureId = `${FileType.ChargingStationConfiguration} write`;
-          const beginId = PerformanceStatistics.beginMeasure(measureId);
-          const fileDescriptor = fs.openSync(this.configurationFile, 'w');
-          fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
-          fs.closeSync(fileDescriptor);
-          PerformanceStatistics.endMeasure(measureId, beginId);
-          this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
-          this.sharedLRUCache.setChargingStationConfiguration(configurationData);
-          this.configurationFileHash = configurationHash;
+          AsyncLock.acquire(AsyncLockType.configuration)
+            .then(() => {
+              configurationData.configurationHash = configurationHash;
+              const measureId = `${FileType.ChargingStationConfiguration} write`;
+              const beginId = PerformanceStatistics.beginMeasure(measureId);
+              const fileDescriptor = fs.openSync(this.configurationFile, 'w');
+              fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
+              fs.closeSync(fileDescriptor);
+              PerformanceStatistics.endMeasure(measureId, beginId);
+              this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
+              this.sharedLRUCache.setChargingStationConfiguration(configurationData);
+              this.configurationFileHash = configurationHash;
+            })
+            .catch((error) => {
+              ErrorUtils.handleFileException(
+                this.configurationFile,
+                FileType.ChargingStationConfiguration,
+                error as NodeJS.ErrnoException,
+                this.logPrefix()
+              );
+            })
+            .finally(() => {
+              AsyncLock.release(AsyncLockType.configuration).catch(Constants.EMPTY_FUNCTION);
+            });
         } else {
           logger.debug(
             `${this.logPrefix()} Not saving unchanged charging station configuration file ${
@@ -1565,7 +1613,7 @@ export class ChargingStation {
           );
         }
       } catch (error) {
-        FileUtils.handleFileException(
+        ErrorUtils.handleFileException(
           this.configurationFile,
           FileType.ChargingStationConfiguration,
           error as NodeJS.ErrnoException,
@@ -1584,16 +1632,11 @@ export class ChargingStation {
   }
 
   private getOcppConfigurationFromFile(): ChargingStationOcppConfiguration | undefined {
-    let configuration: ChargingStationConfiguration | undefined;
-    if (this.getOcppPersistentConfiguration() === true) {
-      const configurationFromFile = this.getConfigurationFromFile();
-      configuration = configurationFromFile?.configurationKey && configurationFromFile;
-    }
-    if (!Utils.isNullOrUndefined(configuration)) {
-      delete configuration.stationInfo;
-      delete configuration.configurationHash;
+    const configurationKey = this.getConfigurationFromFile()?.configurationKey;
+    if (this.getOcppPersistentConfiguration() === true && configurationKey) {
+      return { configurationKey };
     }
-    return configuration;
+    return undefined;
   }
 
   private getOcppConfiguration(): ChargingStationOcppConfiguration | undefined {
@@ -1621,11 +1664,11 @@ 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
-                : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL
+                : Constants.DEFAULT_BOOT_NOTIFICATION_INTERVAL
             );
           }
         } while (
@@ -1635,7 +1678,7 @@ export class ChargingStation {
         );
       }
       if (this.isRegistered() === true) {
-        if (this.isInAcceptedState() === true) {
+        if (this.inAcceptedState() === true) {
           await this.startMessageSequence();
         }
       } else {
@@ -1984,7 +2027,8 @@ export class ChargingStation {
             await OCPPServiceUtils.sendAndSetConnectorStatus(
               this,
               connectorId,
-              connectorBootStatus
+              connectorBootStatus,
+              evseId
             );
           }
         }
@@ -2012,7 +2056,7 @@ export class ChargingStation {
     }
 
     // Start the ATG
-    if (this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true) {
+    if (this.getAutomaticTransactionGeneratorConfiguration()?.enable === true) {
       this.startAutomaticTransactionGenerator();
     }
     this.wsConnectionRestarted === true && this.flushMessageBuffer();
@@ -2044,7 +2088,8 @@ export class ChargingStation {
               OCPPServiceUtils.buildStatusNotificationRequest(
                 this,
                 connectorId,
-                ConnectorStatusEnum.Unavailable
+                ConnectorStatusEnum.Unavailable,
+                evseId
               )
             );
             delete connectorStatus?.status;
@@ -2116,6 +2161,7 @@ export class ChargingStation {
   }
 
   private getConfiguredSupervisionUrl(): URL {
+    let configuredSupervisionUrl: string;
     const supervisionUrls = this.stationInfo?.supervisionUrls ?? Configuration.getSupervisionUrls();
     if (Utils.isNotEmptyArray(supervisionUrls)) {
       let configuredSupervisionUrlIndex: number;
@@ -2137,9 +2183,16 @@ export class ChargingStation {
           configuredSupervisionUrlIndex = (this.index - 1) % supervisionUrls.length;
           break;
       }
-      return new URL(supervisionUrls[configuredSupervisionUrlIndex]);
+      configuredSupervisionUrl = supervisionUrls[configuredSupervisionUrlIndex];
+    } else {
+      configuredSupervisionUrl = supervisionUrls as string;
+    }
+    if (Utils.isNotEmptyString(configuredSupervisionUrl)) {
+      return new URL(configuredSupervisionUrl);
     }
-    return new URL(supervisionUrls as string);
+    const errorMsg = 'No supervision url(s) configured';
+    logger.error(`${this.logPrefix()} ${errorMsg}`);
+    throw new BaseError(`${errorMsg}`);
   }
 
   private stopHeartbeat(): void {
@@ -2166,14 +2219,14 @@ export class ChargingStation {
     // Stop heartbeat
     this.stopHeartbeat();
     // Stop the ATG if needed
-    if (this.automaticTransactionGenerator?.configuration?.stopOnConnectionFailure === true) {
+    if (this.getAutomaticTransactionGeneratorConfiguration().stopOnConnectionFailure === true) {
       this.stopAutomaticTransactionGenerator();
     }
     if (
       this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() ||
       this.getAutoReconnectMaxRetries() === -1
     ) {
-      this.autoReconnectRetryCount++;
+      ++this.autoReconnectRetryCount;
       const reconnectDelay = this.getReconnectExponentialDelay()
         ? Utils.exponentialDelay(this.autoReconnectRetryCount)
         : this.getConnectionTimeout() * 1000;
@@ -2208,10 +2261,4 @@ export class ChargingStation {
       );
     }
   }
-
-  private getAutomaticTransactionGeneratorConfigurationFromTemplate():
-    | AutomaticTransactionGeneratorConfiguration
-    | undefined {
-    return this.getTemplateFromFile()?.AutomaticTransactionGenerator;
-  }
 }