+ if (this.started === false) {
+ if (this.starting === false) {
+ this.starting = true;
+ if (this.getEnableStatistics() === true) {
+ this.performanceStatistics?.start();
+ }
+ if (hasFeatureProfile(this, SupportedFeatureProfiles.Reservation)) {
+ this.startReservationExpirationSetInterval();
+ }
+ this.openWSConnection();
+ // Monitor charging station template file
+ this.templateFileWatcher = watchJsonFile(
+ this.templateFile,
+ FileType.ChargingStationTemplate,
+ this.logPrefix(),
+ undefined,
+ (event, filename): void => {
+ if (isNotEmptyString(filename) && event === 'change') {
+ try {
+ logger.debug(
+ `${this.logPrefix()} ${FileType.ChargingStationTemplate} ${
+ this.templateFile
+ } file have changed, reload`,
+ );
+ this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
+ // Initialize
+ this.initialize();
+ this.idTagsCache.deleteIdTags(getIdTagsFile(this.stationInfo)!);
+ // Restart the ATG
+ this.stopAutomaticTransactionGenerator();
+ delete this.automaticTransactionGeneratorConfiguration;
+ if (this.getAutomaticTransactionGeneratorConfiguration()?.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(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();
+ }
+ if (hasFeatureProfile(this, SupportedFeatureProfiles.Reservation)) {
+ this.stopReservationExpirationSetInterval();
+ }
+ this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
+ this.templateFileWatcher?.close();
+ this.sharedLRUCache.deleteChargingStationTemplate(this.templateFileHash);
+ delete this.bootNotificationResponse;
+ this.started = false;
+ this.saveConfiguration();
+ parentPort?.postMessage(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 sleep(this.stationInfo.resetTime!);
+ this.initialize();
+ this.start();
+ }
+
+ public saveOcppConfiguration(): void {
+ if (this.getOcppPersistentConfiguration()) {
+ this.saveConfiguration();
+ }
+ }
+
+ public bufferMessage(message: string): void {
+ this.messageBuffer.add(message);
+ }
+
+ public openWSConnection(
+ options?: WsOptions,
+ params?: { closeOpened?: boolean; terminateOpened?: boolean },
+ ): void {
+ options = {
+ handshakeTimeout: secondsToMilliseconds(this.getConnectionTimeout()),
+ ...this.stationInfo?.wsOptions,
+ ...options,
+ };
+ params = { ...{ closeOpened: false, terminateOpened: false }, ...params };
+ if (!checkChargingStation(this, this.logPrefix())) {
+ return;
+ }
+ if (
+ !isNullOrUndefined(this.stationInfo.supervisionUser) &&
+ !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;