Add tunable in template to disable limitation on custom metervalues
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index a9aaab7975e0a5645f9de4c7f7b2fdec5673e16e..8dc9135fa7b80e314b0880214fd029f0f7c9a8db 100644 (file)
@@ -126,12 +126,12 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ]);
   }
 
-  public async handleRequest(
+  public async incomingRequestHandler(
     messageId: string,
     commandName: OCPP16IncomingRequestCommand,
     commandPayload: JsonType
   ): Promise<void> {
-    let result: JsonType;
+    let response: JsonType;
     if (
       this.chargingStation.getOcppStrictCompliance() &&
       this.chargingStation.isInPendingState() &&
@@ -154,8 +154,8 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ) {
       if (this.incomingRequestHandlers.has(commandName)) {
         try {
-          // Call the method to build the result
-          result = await this.incomingRequestHandlers.get(commandName)(commandPayload);
+          // 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);
@@ -184,19 +184,17 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         commandName
       );
     }
-    // Send the built result
-    await this.chargingStation.ocppRequestService.sendResult(messageId, result, commandName);
+    // Send the built response
+    await this.chargingStation.ocppRequestService.sendResponse(messageId, response, commandName);
   }
 
   // Simulate charging station restart
   private handleRequestReset(commandPayload: ResetRequest): DefaultResponse {
     // eslint-disable-next-line @typescript-eslint/no-misused-promises
     setImmediate(async (): Promise<void> => {
-      await this.chargingStation.stop(
+      await this.chargingStation.reset(
         (commandPayload.type + 'Reset') as OCPP16StopTransactionReason
       );
-      await Utils.sleep(this.chargingStation.stationInfo.resetTime);
-      this.chargingStation.start();
     });
     logger.info(
       `${this.chargingStation.logPrefix()} ${
@@ -235,7 +233,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           connectorId,
           this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId)
         );
-        await this.chargingStation.ocppRequestService.sendMessageHandler<
+        await this.chargingStation.ocppRequestService.requestHandler<
           OCPP16MeterValuesRequest,
           OCPP16MeterValuesResponse
         >(OCPP16RequestCommand.METER_VALUES, {
@@ -244,7 +242,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           meterValue: transactionEndMeterValue,
         });
       }
-      const stopResponse = await this.chargingStation.ocppRequestService.sendMessageHandler<
+      const stopResponse = await this.chargingStation.ocppRequestService.requestHandler<
         OCPP16StopTransactionRequest,
         OCPP16StopTransactionResponse
       >(OCPP16RequestCommand.STOP_TRANSACTION, {
@@ -258,7 +256,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       }
       return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
     }
-    await this.chargingStation.ocppRequestService.sendMessageHandler<
+    await this.chargingStation.ocppRequestService.requestHandler<
       OCPP16StatusNotificationRequest,
       OCPP16StatusNotificationResponse
     >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
@@ -381,14 +379,13 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestSetChargingProfile(
     commandPayload: SetChargingProfileRequest
   ): SetChargingProfileResponse {
-    if (!this.chargingStation.hasFeatureProfile(OCPP16SupportedFeatureProfiles.Smart_Charging)) {
-      logger.error(
-        `${this.chargingStation.logPrefix()} Trying to set charging profile(s) without '${
-          OCPP16SupportedFeatureProfiles.Smart_Charging
-        }' feature enabled in ${
-          OCPP16StandardParametersKey.SupportedFeatureProfiles
-        } in configuration`
-      );
+    if (
+      !OCPP16ServiceUtils.checkFeatureProfile(
+        this.chargingStation,
+        OCPP16SupportedFeatureProfiles.SmartCharging,
+        OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE
+      )
+    ) {
       return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED;
     }
     if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) {
@@ -430,14 +427,13 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestClearChargingProfile(
     commandPayload: ClearChargingProfileRequest
   ): ClearChargingProfileResponse {
-    if (!this.chargingStation.hasFeatureProfile(OCPP16SupportedFeatureProfiles.Smart_Charging)) {
-      logger.error(
-        `${this.chargingStation.logPrefix()} Trying to clear charging profile(s) without '${
-          OCPP16SupportedFeatureProfiles.Smart_Charging
-        }' feature enabled in ${
-          OCPP16StandardParametersKey.SupportedFeatureProfiles
-        } in configuration`
-      );
+    if (
+      !OCPP16ServiceUtils.checkFeatureProfile(
+        this.chargingStation,
+        OCPP16SupportedFeatureProfiles.SmartCharging,
+        OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE
+      )
+    ) {
       return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
     }
     const connectorStatus = this.chargingStation.getConnectorStatus(commandPayload.connectorId);
@@ -532,7 +528,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         }
         this.chargingStation.getConnectorStatus(id).availability = commandPayload.type;
         if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
-          await this.chargingStation.ocppRequestService.sendMessageHandler<
+          await this.chargingStation.ocppRequestService.requestHandler<
             OCPP16StatusNotificationRequest,
             OCPP16StatusNotificationResponse
           >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
@@ -557,7 +553,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
       }
       this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
-      await this.chargingStation.ocppRequestService.sendMessageHandler<
+      await this.chargingStation.ocppRequestService.requestHandler<
         OCPP16StatusNotificationRequest,
         OCPP16StatusNotificationResponse
       >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
@@ -577,7 +573,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     const transactionConnectorId = commandPayload.connectorId;
     const connectorStatus = this.chargingStation.getConnectorStatus(transactionConnectorId);
     if (transactionConnectorId) {
-      await this.chargingStation.ocppRequestService.sendMessageHandler<
+      await this.chargingStation.ocppRequestService.requestHandler<
         OCPP16StatusNotificationRequest,
         OCPP16StatusNotificationResponse
       >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
@@ -601,7 +597,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           } else if (this.chargingStation.getMayAuthorizeAtRemoteStart()) {
             connectorStatus.authorizeIdTag = commandPayload.idTag;
             const authorizeResponse: OCPP16AuthorizeResponse =
-              await this.chargingStation.ocppRequestService.sendMessageHandler<
+              await this.chargingStation.ocppRequestService.requestHandler<
                 OCPP16AuthorizeRequest,
                 OCPP16AuthorizeResponse
               >(OCPP16RequestCommand.AUTHORIZE, {
@@ -626,7 +622,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
               connectorStatus.transactionRemoteStarted = true;
               if (
                 (
-                  await this.chargingStation.ocppRequestService.sendMessageHandler<
+                  await this.chargingStation.ocppRequestService.requestHandler<
                     OCPP16StartTransactionRequest,
                     OCPP16StartTransactionResponse
                   >(OCPP16RequestCommand.START_TRANSACTION, {
@@ -671,7 +667,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           connectorStatus.transactionRemoteStarted = true;
           if (
             (
-              await this.chargingStation.ocppRequestService.sendMessageHandler<
+              await this.chargingStation.ocppRequestService.requestHandler<
                 OCPP16StartTransactionRequest,
                 OCPP16StartTransactionResponse
               >(OCPP16RequestCommand.START_TRANSACTION, {
@@ -717,7 +713,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       this.chargingStation.getConnectorStatus(connectorId).status !==
       OCPP16ChargePointStatus.AVAILABLE
     ) {
-      await this.chargingStation.ocppRequestService.sendMessageHandler<
+      await this.chargingStation.ocppRequestService.requestHandler<
         OCPP16StatusNotificationRequest,
         OCPP16StatusNotificationResponse
       >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
@@ -774,7 +770,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         connectorId > 0 &&
         this.chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
       ) {
-        await this.chargingStation.ocppRequestService.sendMessageHandler<
+        await this.chargingStation.ocppRequestService.requestHandler<
           OCPP16StatusNotificationRequest,
           OCPP16StatusNotificationResponse
         >(OCPP16RequestCommand.STATUS_NOTIFICATION, {
@@ -795,7 +791,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
             connectorId,
             this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId)
           );
-          await this.chargingStation.ocppRequestService.sendMessageHandler<
+          await this.chargingStation.ocppRequestService.requestHandler<
             OCPP16MeterValuesRequest,
             OCPP16MeterValuesResponse
           >(OCPP16RequestCommand.METER_VALUES, {
@@ -804,7 +800,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
             meterValue: transactionEndMeterValue,
           });
         }
-        await this.chargingStation.ocppRequestService.sendMessageHandler<
+        await this.chargingStation.ocppRequestService.requestHandler<
           OCPP16StopTransactionRequest,
           OCPP16StopTransactionResponse
         >(OCPP16RequestCommand.STOP_TRANSACTION, {
@@ -828,15 +824,12 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     commandPayload: GetDiagnosticsRequest
   ): Promise<GetDiagnosticsResponse> {
     if (
-      !this.chargingStation.hasFeatureProfile(OCPP16SupportedFeatureProfiles.Firmware_Management)
+      !OCPP16ServiceUtils.checkFeatureProfile(
+        this.chargingStation,
+        OCPP16SupportedFeatureProfiles.FirmwareManagement,
+        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
+      )
     ) {
-      logger.error(
-        `${this.chargingStation.logPrefix()} Trying to get diagnostics without '${
-          OCPP16SupportedFeatureProfiles.Firmware_Management
-        }' feature enabled in ${
-          OCPP16StandardParametersKey.SupportedFeatureProfiles
-        } in configuration`
-      );
       return Constants.OCPP_RESPONSE_EMPTY;
     }
     logger.debug(
@@ -873,7 +866,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
                 info.bytes / 1024
               } bytes transferred from diagnostics archive ${info.name}`
             );
-            await this.chargingStation.ocppRequestService.sendMessageHandler<
+            await this.chargingStation.ocppRequestService.requestHandler<
               DiagnosticsStatusNotificationRequest,
               DiagnosticsStatusNotificationResponse
             >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
@@ -885,7 +878,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
             uri.pathname + diagnosticsArchive
           );
           if (uploadResponse.code === 226) {
-            await this.chargingStation.ocppRequestService.sendMessageHandler<
+            await this.chargingStation.ocppRequestService.requestHandler<
               DiagnosticsStatusNotificationRequest,
               DiagnosticsStatusNotificationResponse
             >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
@@ -912,7 +905,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
         );
       } catch (error) {
-        await this.chargingStation.ocppRequestService.sendMessageHandler<
+        await this.chargingStation.ocppRequestService.requestHandler<
           DiagnosticsStatusNotificationRequest,
           DiagnosticsStatusNotificationResponse
         >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
@@ -933,7 +926,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
           uri.protocol
         } to transfer the diagnostic logs archive`
       );
-      await this.chargingStation.ocppRequestService.sendMessageHandler<
+      await this.chargingStation.ocppRequestService.requestHandler<
         DiagnosticsStatusNotificationRequest,
         DiagnosticsStatusNotificationResponse
       >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
@@ -946,22 +939,30 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestTriggerMessage(
     commandPayload: OCPP16TriggerMessageRequest
   ): OCPP16TriggerMessageResponse {
-    if (!this.chargingStation.hasFeatureProfile(OCPP16SupportedFeatureProfiles.Remote_Trigger)) {
-      logger.error(
-        `${this.chargingStation.logPrefix()} Trying to remote trigger message without '${
-          OCPP16SupportedFeatureProfiles.Remote_Trigger
-        }' feature enabled in ${
-          OCPP16StandardParametersKey.SupportedFeatureProfiles
-        } in configuration`
-      );
+    if (
+      !OCPP16ServiceUtils.checkFeatureProfile(
+        this.chargingStation,
+        OCPP16SupportedFeatureProfiles.RemoteTrigger,
+        OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
+      )
+    ) {
       return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
     }
+    // TODO: factor out the check on connector id
+    if (commandPayload?.connectorId < 0) {
+      logger.warn(
+        `${this.chargingStation.logPrefix()} ${
+          OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
+        } incoming request received with invalid connectorId ${commandPayload.connectorId}`
+      );
+      return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED;
+    }
     try {
       switch (commandPayload.requestedMessage) {
         case MessageTrigger.BootNotification:
           setTimeout(() => {
             this.chargingStation.ocppRequestService
-              .sendMessageHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
+              .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
                 OCPP16RequestCommand.BOOT_NOTIFICATION,
                 {
                   chargePointModel:
@@ -993,7 +994,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         case MessageTrigger.Heartbeat:
           setTimeout(() => {
             this.chargingStation.ocppRequestService
-              .sendMessageHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
+              .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
                 OCPP16RequestCommand.HEARTBEAT,
                 null,
                 {
@@ -1005,6 +1006,49 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
               });
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
+        case MessageTrigger.StatusNotification:
+          setTimeout(() => {
+            if (commandPayload?.connectorId) {
+              this.chargingStation.ocppRequestService
+                .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
+                  OCPP16RequestCommand.STATUS_NOTIFICATION,
+                  {
+                    connectorId: commandPayload.connectorId,
+                    errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                    status: this.chargingStation.getConnectorStatus(commandPayload.connectorId)
+                      .status,
+                  },
+                  {
+                    triggerMessage: true,
+                  }
+                )
+                .catch(() => {
+                  /* This is intentional */
+                });
+            } else {
+              for (const connectorId of this.chargingStation.connectors.keys()) {
+                this.chargingStation.ocppRequestService
+                  .requestHandler<
+                    OCPP16StatusNotificationRequest,
+                    OCPP16StatusNotificationResponse
+                  >(
+                    OCPP16RequestCommand.STATUS_NOTIFICATION,
+                    {
+                      connectorId,
+                      errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
+                      status: this.chargingStation.getConnectorStatus(connectorId).status,
+                    },
+                    {
+                      triggerMessage: true,
+                    }
+                  )
+                  .catch(() => {
+                    /* This is intentional */
+                  });
+              }
+            }
+          }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
+          return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         default:
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
       }