Refactor OCPP requests sending helpers
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index 6510e68f38c57ca5053e3871cda6aaa01b38dfa6..9377c605cb94a966c201361311f5eae4e0394fc5 100644 (file)
@@ -11,12 +11,12 @@ import Constants from '../../../utils/Constants';
 import { DefaultResponse } from '../../../types/ocpp/Responses';
 import { ErrorType } from '../../../types/ocpp/ErrorType';
 import { IncomingRequestHandler } from '../../../types/ocpp/Requests';
-import { MessageType } from '../../../types/ocpp/MessageType';
+import { JsonType } from '../../../types/JsonType';
 import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
 import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
 import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
 import { OCPPConfigurationKey } from '../../../types/ocpp/Configuration';
-import OCPPError from '../OCPPError';
+import OCPPError from '../../../exception/OCPPError';
 import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
 import { URL } from 'url';
 import Utils from '../../../utils/Utils';
@@ -28,7 +28,10 @@ import tar from 'tar';
 export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
   private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
 
-  constructor(chargingStation: ChargingStation) {
+  public constructor(chargingStation: ChargingStation) {
+    if (new.target?.name === 'OCPP16IncomingRequestService') {
+      throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
+    }
     super(chargingStation);
     this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
       [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
@@ -46,23 +49,31 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ]);
   }
 
-  public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record<string, unknown>): Promise<void> {
-    let response: Record<string, unknown>;
-    if (this.incomingRequestHandlers.has(commandName)) {
-      try {
-        // Call the method to build the response
-        response = await this.incomingRequestHandlers.get(commandName)(commandPayload);
-      } catch (error) {
-        // Log
-        logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
-        throw error;
+  public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: JsonType): Promise<void> {
+    let result: JsonType;
+    if (this.chargingStation.getOcppStrictCompliance() && (this.chargingStation.isInPendingState()
+      && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION))) {
+      throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while the charging station is in pending state on the central server`, commandName);
+    }
+    if (this.chargingStation.isRegistered() || (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState())) {
+      if (this.incomingRequestHandlers.has(commandName)) {
+        try {
+          // Call the method to build the result
+          result = await this.incomingRequestHandlers.get(commandName)(commandPayload);
+        } catch (error) {
+          // Log
+          logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error);
+          throw error;
+        }
+      } else {
+        // Throw exception
+        throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request payload ${JSON.stringify(commandPayload, null, 2)}`, commandName);
       }
     } else {
-      // Throw exception
-      throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request payload ${JSON.stringify(commandPayload, null, 2)}`, commandName);
+      throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while the charging station is not registered on the central server.`, commandName);
     }
-    // Send the built response
-    await this.chargingStation.ocppRequestService.sendMessage(messageId, response, MessageType.CALL_RESULT_MESSAGE, commandName);
+    // Send the built result
+    await this.chargingStation.ocppRequestService.sendResult(messageId, result, commandName);
   }
 
   // Simulate charging station restart
@@ -292,7 +303,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         if (this.chargingStation.getAuthorizeRemoteTxRequests()) {
           let authorized = false;
           if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()
-              && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
+            && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
             this.chargingStation.getConnectorStatus(transactionConnectorId).localAuthorizeIdTag = commandPayload.idTag;
             this.chargingStation.getConnectorStatus(transactionConnectorId).idTagLocalAuthorized = true;
             authorized = true;
@@ -426,12 +437,15 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           setTimeout(() => {
             this.chargingStation.ocppRequestService.sendBootNotification(this.chargingStation.getBootNotificationRequest().chargePointModel,
               this.chargingStation.getBootNotificationRequest().chargePointVendor, this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
-              this.chargingStation.getBootNotificationRequest().firmwareVersion).catch(() => { /* This is intentional */ });
+              this.chargingStation.getBootNotificationRequest().firmwareVersion, this.chargingStation.getBootNotificationRequest().chargePointSerialNumber,
+              this.chargingStation.getBootNotificationRequest().iccid, this.chargingStation.getBootNotificationRequest().imsi,
+              this.chargingStation.getBootNotificationRequest().meterSerialNumber, this.chargingStation.getBootNotificationRequest().meterType,
+              { triggerMessage: true }).catch(() => { /* This is intentional */ });
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         case MessageTrigger.Heartbeat:
           setTimeout(() => {
-            this.chargingStation.ocppRequestService.sendHeartbeat().catch(() => { /* This is intentional */ });
+            this.chargingStation.ocppRequestService.sendHeartbeat({ triggerMessage: true }).catch(() => { /* This is intentional */ });
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         default: