Add status notification support to trigger message OCPP command
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index a9aaab7975e0a5645f9de4c7f7b2fdec5673e16e..6df6f75f09c08f9be541a6bd7de025aab8c46574 100644 (file)
@@ -126,7 +126,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ]);
   }
 
-  public async handleRequest(
+  public async incomingRequestHandler(
     messageId: string,
     commandName: OCPP16IncomingRequestCommand,
     commandPayload: JsonType
@@ -235,7 +235,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 +244,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 +258,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 +381,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 +429,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 +530,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 +555,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 +575,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 +599,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 +624,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 +669,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 +715,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 +772,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 +793,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 +802,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 +826,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 +868,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 +880,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 +907,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 +928,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 +941,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 +996,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 +1008,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;
       }