Fix worker startup and cleanup some attributes in Wrk class.
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStation.ts
index 8c0b04c14eef985978a83d24ff2f4151e7d80247..8341fe30a71612a1b52ff5da90ca5245dde53d09 100644 (file)
@@ -1,9 +1,9 @@
-import { AuthorizationStatus, StartTransactionRequest, StartTransactionResponse, StopTransactionReason, StopTransactionRequest, StopTransactionResponse } from '../types/ocpp/1.6/Transaction';
+import { AuthorizationStatus, AuthorizeRequest, AuthorizeResponse, StartTransactionRequest, StartTransactionResponse, StopTransactionReason, StopTransactionRequest, StopTransactionResponse } from '../types/ocpp/1.6/Transaction';
 import { AvailabilityType, BootNotificationRequest, ChangeAvailabilityRequest, ChangeConfigurationRequest, GetConfigurationRequest, HeartbeatRequest, IncomingRequestCommand, RemoteStartTransactionRequest, RemoteStopTransactionRequest, RequestCommand, ResetRequest, SetChargingProfileRequest, StatusNotificationRequest, UnlockConnectorRequest } from '../types/ocpp/1.6/Requests';
 import { BootNotificationResponse, ChangeAvailabilityResponse, ChangeConfigurationResponse, DefaultResponse, GetConfigurationResponse, HeartbeatResponse, RegistrationStatus, SetChargingProfileResponse, StatusNotificationResponse, UnlockConnectorResponse } from '../types/ocpp/1.6/RequestResponses';
 import { ChargingProfile, ChargingProfilePurposeType } from '../types/ocpp/1.6/ChargingProfile';
 import ChargingStationConfiguration, { ConfigurationKey } from '../types/ChargingStationConfiguration';
-import ChargingStationTemplate, { PowerOutType } from '../types/ChargingStationTemplate';
+import ChargingStationTemplate, { PowerOutType, VoltageOut } from '../types/ChargingStationTemplate';
 import Connectors, { Connector } from '../types/Connectors';
 import { MeterValue, MeterValueLocation, MeterValueMeasurand, MeterValuePhase, MeterValueUnit, MeterValuesRequest, MeterValuesResponse, SampledValue } from '../types/ocpp/1.6/MeterValues';
 import { PerformanceObserver, performance } from 'perf_hooks';
@@ -71,7 +71,13 @@ export default class ChargingStation {
   }
 
   _getStationName(stationTemplate: ChargingStationTemplate): string {
-    return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + ('000000000' + this._index.toString()).substr(('000000000' + this._index.toString()).length - 4);
+    // In case of multiple instances: add instance index to charging station id
+    let instanceIndex = process.env.CF_INSTANCE_INDEX ? process.env.CF_INSTANCE_INDEX : 0;
+    instanceIndex = instanceIndex > 0 ? instanceIndex : '';
+
+    const idSuffix = stationTemplate.nameSuffix ? stationTemplate.nameSuffix : '';
+
+    return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + instanceIndex.toString() + ('000000000' + this._index.toString()).substr(('000000000' + this._index.toString()).length - 4) + idSuffix;
   }
 
   _buildStationInfo(): ChargingStationInfo {
@@ -335,10 +341,10 @@ export default class ChargingStation {
     let defaultVoltageOut: number;
     switch (this._getPowerOutType()) {
       case PowerOutType.AC:
-        defaultVoltageOut = 230;
+        defaultVoltageOut = VoltageOut.VOLTAGE_230;
         break;
       case PowerOutType.DC:
-        defaultVoltageOut = 400;
+        defaultVoltageOut = VoltageOut.VOLTAGE_400;
         break;
       default:
         logger.error(errMsg);
@@ -521,8 +527,7 @@ export default class ChargingStation {
   }
 
   _startAuthorizationFileMonitoring(): void {
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    fs.watchFile(this._getAuthorizationFile(), (current, previous) => {
+    fs.watch(this._getAuthorizationFile()).on('change', (e) => {
       try {
         logger.debug(this._logPrefix() + ' Authorization file ' + this._getAuthorizationFile() + ' have changed, reload');
         // Initialize _authorizedTags
@@ -534,16 +539,25 @@ export default class ChargingStation {
   }
 
   _startStationTemplateFileMonitoring(): void {
-    // eslint-disable-next-line @typescript-eslint/no-unused-vars
-    fs.watchFile(this._stationTemplateFile, (current, previous) => {
+    fs.watch(this._stationTemplateFile).on('change', (e) => {
       try {
         logger.debug(this._logPrefix() + ' Template file ' + this._stationTemplateFile + ' have changed, reload');
         // Initialize
         this._initialize();
+        // Stop the ATG
         if (!this._stationInfo.AutomaticTransactionGenerator.enable &&
           this._automaticTransactionGeneration) {
           this._automaticTransactionGeneration.stop().catch(() => { });
         }
+        // Start the ATG
+        if (this._stationInfo.AutomaticTransactionGenerator.enable) {
+          if (!this._automaticTransactionGeneration) {
+            this._automaticTransactionGeneration = new AutomaticTransactionGenerator(this);
+          }
+          if (this._automaticTransactionGeneration.timeToStop) {
+            this._automaticTransactionGeneration.start();
+          }
+        }
         // FIXME?: restart heartbeat and WebSocket ping when their interval values have changed
       } catch (error) {
         logger.error(this._logPrefix() + ' Charging station template file monitoring error: %j', error);
@@ -580,7 +594,7 @@ export default class ChargingStation {
         }
       }, interval);
     } else {
-      logger.error(`${this._logPrefix()} Charging station MeterValueSampleInterval configuration set to ${Utils.milliSecondsToHHMMSS(interval)}, not sending MeterValues`);
+      logger.error(`${this._logPrefix()} Charging station ${StandardParametersKey.MeterValueSampleInterval} configuration set to ${Utils.milliSecondsToHHMMSS(interval)}, not sending MeterValues`);
     }
   }
 
@@ -811,11 +825,22 @@ export default class ChargingStation {
     }
   }
 
+  async sendAuthorize(idTag?: string): Promise<AuthorizeResponse> {
+    try {
+      const payload: AuthorizeRequest = {
+        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID },
+      };
+      return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, RequestCommand.AUTHORIZE) as AuthorizeResponse;
+    } catch (error) {
+      this.handleRequestError(RequestCommand.AUTHORIZE, error);
+    }
+  }
+
   async sendStartTransaction(connectorId: number, idTag?: string): Promise<StartTransactionResponse> {
     try {
       const payload: StartTransactionRequest = {
         connectorId,
-        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG },
+        ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID },
         meterStart: 0,
         timestamp: new Date().toISOString(),
       };
@@ -984,7 +1009,7 @@ export default class ChargingStation {
       return;
     }
 
-    if (payload.idTagInfo.status === AuthorizationStatus.ACCEPTED) {
+    if (payload?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
       this.getConnector(connectorId).transactionStarted = true;
       this.getConnector(connectorId).transactionId = payload.transactionId;
       this.getConnector(connectorId).idTag = requestPayload.idTag;
@@ -998,7 +1023,7 @@ export default class ChargingStation {
       this._startMeterValues(connectorId,
         configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
     } else {
-      logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo.status + ', idTag ' + requestPayload.idTag);
+      logger.error(this._logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
       this._resetTransactionOnConnector(connectorId);
       await this.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE);
     }