Add status notification support to trigger message OCPP command
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
index 7e04e6bf4b6423e745682c2f7f6ff035a2590b01..6df6f75f09c08f9be541a6bd7de025aab8c46574 100644 (file)
@@ -54,6 +54,10 @@ import {
   OCPP16MeterValuesRequest,
   OCPP16MeterValuesResponse,
 } from '../../../types/ocpp/1.6/MeterValues';
+import {
+  OCPP16StandardParametersKey,
+  OCPP16SupportedFeatureProfiles,
+} from '../../../types/ocpp/1.6/Configuration';
 
 import type ChargingStation from '../../ChargingStation';
 import Constants from '../../../utils/Constants';
@@ -65,7 +69,6 @@ import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointE
 import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
 import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
-import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
 import { OCPPConfigurationKey } from '../../../types/ocpp/Configuration';
 import OCPPError from '../../../exception/OCPPError';
 import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
@@ -123,7 +126,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     ]);
   }
 
-  public async handleRequest(
+  public async incomingRequestHandler(
     messageId: string,
     commandName: OCPP16IncomingRequestCommand,
     commandPayload: JsonType
@@ -232,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, {
@@ -241,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, {
@@ -255,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, {
@@ -378,6 +381,15 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestSetChargingProfile(
     commandPayload: SetChargingProfileRequest
   ): SetChargingProfileResponse {
+    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)) {
       logger.error(
         `${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${
@@ -417,6 +429,15 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestClearChargingProfile(
     commandPayload: ClearChargingProfileRequest
   ): ClearChargingProfileResponse {
+    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);
     if (!connectorStatus) {
       logger.error(
@@ -509,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, {
@@ -534,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, {
@@ -554,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, {
@@ -578,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, {
@@ -603,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, {
@@ -648,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, {
@@ -694,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, {
@@ -751,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, {
@@ -772,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, {
@@ -781,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, {
@@ -804,6 +825,15 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private async handleRequestGetDiagnostics(
     commandPayload: GetDiagnosticsRequest
   ): Promise<GetDiagnosticsResponse> {
+    if (
+      !OCPP16ServiceUtils.checkFeatureProfile(
+        this.chargingStation,
+        OCPP16SupportedFeatureProfiles.FirmwareManagement,
+        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
+      )
+    ) {
+      return Constants.OCPP_RESPONSE_EMPTY;
+    }
     logger.debug(
       this.chargingStation.logPrefix() +
         ' ' +
@@ -838,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, {
@@ -850,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, {
@@ -877,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, {
@@ -898,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, {
@@ -911,12 +941,30 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestTriggerMessage(
     commandPayload: OCPP16TriggerMessageRequest
   ): OCPP16TriggerMessageResponse {
+    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:
@@ -948,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,
                 {
@@ -960,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;
       }