+ if (this.started === false) {
+ if (this.starting === false) {
+ this.starting = true;
+ if (this.getEnableStatistics() === true) {
+ this.performanceStatistics?.start();
+ }
+ this.openWSConnection();
+ // Monitor charging station template file
+ this.templateFileWatcher = FileUtils.watchJsonFile(
+ this.templateFile,
+ FileType.ChargingStationTemplate,
+ this.logPrefix(),
+ undefined,
+ (event, filename): void => {
+ if (Utils.isNotEmptyString(filename) && event === 'change') {
+ try {
+ logger.debug(
+ `${this.logPrefix()} ${FileType.ChargingStationTemplate} ${
+ this.templateFile
+ } file have changed, reload`
+ );
+ this.sharedLRUCache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
+ // Initialize
+ this.initialize();
+ // Restart the ATG
+ this.stopAutomaticTransactionGenerator();
+ if (
+ this.getAutomaticTransactionGeneratorConfigurationFromTemplate()?.enable === true
+ ) {
+ this.startAutomaticTransactionGenerator();
+ }
+ if (this.getEnableStatistics() === true) {
+ this.performanceStatistics?.restart();
+ } else {
+ this.performanceStatistics?.stop();
+ }
+ // FIXME?: restart heartbeat and WebSocket ping when their interval values have changed
+ } catch (error) {
+ logger.error(
+ `${this.logPrefix()} ${FileType.ChargingStationTemplate} file monitoring error:`,
+ error
+ );
+ }
+ }
+ }
+ );
+ this.started = true;
+ parentPort?.postMessage(MessageChannelUtils.buildStartedMessage(this));
+ this.starting = false;
+ } else {
+ logger.warn(`${this.logPrefix()} Charging station is already starting...`);
+ }
+ } else {
+ logger.warn(`${this.logPrefix()} Charging station is already started...`);
+ }
+ }
+
+ public async stop(reason?: StopTransactionReason): Promise<void> {
+ if (this.started === true) {
+ if (this.stopping === false) {
+ this.stopping = true;
+ await this.stopMessageSequence(reason);
+ this.closeWSConnection();
+ if (this.getEnableStatistics() === true) {
+ this.performanceStatistics?.stop();
+ }
+ this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
+ this.templateFileWatcher?.close();
+ this.sharedLRUCache.deleteChargingStationTemplate(this.stationInfo?.templateHash);
+ delete this.bootNotificationResponse;
+ this.started = false;
+ parentPort?.postMessage(MessageChannelUtils.buildStoppedMessage(this));
+ this.stopping = false;
+ } else {
+ logger.warn(`${this.logPrefix()} Charging station is already stopping...`);
+ }
+ } else {
+ logger.warn(`${this.logPrefix()} Charging station is already stopped...`);
+ }
+ }
+
+ public async reset(reason?: StopTransactionReason): Promise<void> {
+ await this.stop(reason);
+ await Utils.sleep(this.stationInfo.resetTime);
+ this.initialize();
+ this.start();
+ }
+
+ public saveOcppConfiguration(): void {
+ if (this.getOcppPersistentConfiguration()) {
+ this.saveConfiguration();
+ }
+ }
+
+ public hasFeatureProfile(featureProfile: SupportedFeatureProfiles): boolean | undefined {
+ return ChargingStationConfigurationUtils.getConfigurationKey(
+ this,
+ StandardParametersKey.SupportedFeatureProfiles
+ )?.value?.includes(featureProfile);
+ }
+
+ public bufferMessage(message: string): void {
+ this.messageBuffer.add(message);
+ }
+
+ public openWSConnection(
+ options: WsOptions = this.stationInfo?.wsOptions ?? {},
+ params: { closeOpened?: boolean; terminateOpened?: boolean } = {
+ closeOpened: false,
+ terminateOpened: false,
+ }
+ ): void {
+ options.handshakeTimeout = options?.handshakeTimeout ?? this.getConnectionTimeout() * 1000;
+ params.closeOpened = params?.closeOpened ?? false;
+ params.terminateOpened = params?.terminateOpened ?? false;
+ if (this.started === false && this.starting === false) {
+ logger.warn(
+ `${this.logPrefix()} Cannot open OCPP connection to URL ${this.wsConnectionUrl.toString()} on stopped charging station`
+ );
+ return;
+ }
+ if (
+ !Utils.isNullOrUndefined(this.stationInfo.supervisionUser) &&
+ !Utils.isNullOrUndefined(this.stationInfo.supervisionPassword)
+ ) {
+ options.auth = `${this.stationInfo.supervisionUser}:${this.stationInfo.supervisionPassword}`;
+ }
+ if (params?.closeOpened) {
+ this.closeWSConnection();
+ }
+ if (params?.terminateOpened) {
+ this.terminateWSConnection();
+ }
+
+ if (this.isWebSocketConnectionOpened() === true) {
+ logger.warn(
+ `${this.logPrefix()} OCPP connection to URL ${this.wsConnectionUrl.toString()} is already opened`
+ );
+ return;