UI Server: refine methods scope
[e-mobility-charging-stations-simulator.git] / src / charging-station / ChargingStationWorkerBroadcastChannel.ts
index 08126286b15d5cbe6ed378e9c41045232347fb76..14d377065d3526b690d2e61c71d17155067cd612 100644 (file)
@@ -1,13 +1,21 @@
 import BaseError from '../exception/BaseError';
 import type OCPPError from '../exception/OCPPError';
+import { StandardParametersKey } from '../types/ocpp/Configuration';
 import {
   HeartbeatRequest,
+  MeterValuesRequest,
   RequestCommand,
   type StatusNotificationRequest,
 } from '../types/ocpp/Requests';
-import type { HeartbeatResponse, StatusNotificationResponse } from '../types/ocpp/Responses';
+import type {
+  HeartbeatResponse,
+  MeterValuesResponse,
+  StatusNotificationResponse,
+} from '../types/ocpp/Responses';
 import {
   AuthorizationStatus,
+  AuthorizeRequest,
+  AuthorizeResponse,
   StartTransactionRequest,
   StartTransactionResponse,
   StopTransactionRequest,
@@ -21,9 +29,12 @@ import {
   MessageEvent,
 } from '../types/WorkerBroadcastChannel';
 import { ResponseStatus } from '../ui/web/src/types/UIProtocol';
+import Constants from '../utils/Constants';
 import logger from '../utils/Logger';
 import Utils from '../utils/Utils';
 import type ChargingStation from './ChargingStation';
+import { ChargingStationConfigurationUtils } from './ChargingStationConfigurationUtils';
+import { OCPP16ServiceUtils } from './ocpp/1.6/OCPP16ServiceUtils';
 import WorkerBroadcastChannel from './WorkerBroadcastChannel';
 
 const moduleName = 'ChargingStationWorkerBroadcastChannel';
@@ -31,24 +42,27 @@ const moduleName = 'ChargingStationWorkerBroadcastChannel';
 type CommandResponse =
   | StartTransactionResponse
   | StopTransactionResponse
+  | AuthorizeResponse
   | StatusNotificationResponse
-  | HeartbeatResponse;
+  | HeartbeatResponse
+  | MeterValuesResponse;
+
+type CommandHandler = (
+  requestPayload?: BroadcastChannelRequestPayload
+) => Promise<CommandResponse | void> | void;
 
 export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadcastChannel {
-  private readonly commandHandlers: Map<
-    BroadcastChannelProcedureName,
-    (requestPayload?: BroadcastChannelRequestPayload) => Promise<CommandResponse> | void
-  >;
+  private readonly commandHandlers: Map<BroadcastChannelProcedureName, CommandHandler>;
 
   private readonly chargingStation: ChargingStation;
 
   constructor(chargingStation: ChargingStation) {
     super();
-    this.commandHandlers = new Map([
+    this.commandHandlers = new Map<BroadcastChannelProcedureName, CommandHandler>([
       [BroadcastChannelProcedureName.START_CHARGING_STATION, () => this.chargingStation.start()],
       [
         BroadcastChannelProcedureName.STOP_CHARGING_STATION,
-        async () => await this.chargingStation.stop(),
+        async () => this.chargingStation.stop(),
       ],
       [
         BroadcastChannelProcedureName.OPEN_CONNECTION,
@@ -58,16 +72,23 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
         BroadcastChannelProcedureName.CLOSE_CONNECTION,
         () => this.chargingStation.closeWSConnection(),
       ],
+      [
+        BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
+        (requestPayload?: BroadcastChannelRequestPayload) =>
+          this.chargingStation.startAutomaticTransactionGenerator(requestPayload.connectorIds),
+      ],
+      [
+        BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
+        (requestPayload?: BroadcastChannelRequestPayload) =>
+          this.chargingStation.stopAutomaticTransactionGenerator(requestPayload.connectorIds),
+      ],
       [
         BroadcastChannelProcedureName.START_TRANSACTION,
         async (requestPayload?: BroadcastChannelRequestPayload) =>
           this.chargingStation.ocppRequestService.requestHandler<
             StartTransactionRequest,
             StartTransactionResponse
-          >(this.chargingStation, RequestCommand.START_TRANSACTION, {
-            connectorId: requestPayload.connectorId,
-            idTag: requestPayload.idTag,
-          }),
+          >(this.chargingStation, RequestCommand.START_TRANSACTION, requestPayload),
       ],
       [
         BroadcastChannelProcedureName.STOP_TRANSACTION,
@@ -76,24 +97,22 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
             StopTransactionRequest,
             StartTransactionResponse
           >(this.chargingStation, RequestCommand.STOP_TRANSACTION, {
-            transactionId: requestPayload.transactionId,
-            meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(
-              requestPayload.transactionId,
-              true
-            ),
-            idTag: requestPayload.idTag,
-            reason: requestPayload.reason,
+            ...requestPayload,
+            meterStop:
+              requestPayload.meterStop ??
+              this.chargingStation.getEnergyActiveImportRegisterByTransactionId(
+                requestPayload.transactionId,
+                true
+              ),
           }),
       ],
       [
-        BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
-        (requestPayload?: BroadcastChannelRequestPayload) =>
-          this.chargingStation.startAutomaticTransactionGenerator(requestPayload.connectorIds),
-      ],
-      [
-        BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
-        (requestPayload?: BroadcastChannelRequestPayload) =>
-          this.chargingStation.stopAutomaticTransactionGenerator(requestPayload.connectorIds),
+        BroadcastChannelProcedureName.AUTHORIZE,
+        async (requestPayload?: BroadcastChannelRequestPayload) =>
+          this.chargingStation.ocppRequestService.requestHandler<
+            AuthorizeRequest,
+            AuthorizeResponse
+          >(this.chargingStation, RequestCommand.AUTHORIZE, requestPayload),
       ],
       [
         BroadcastChannelProcedureName.STATUS_NOTIFICATION,
@@ -101,28 +120,40 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
           this.chargingStation.ocppRequestService.requestHandler<
             StatusNotificationRequest,
             StatusNotificationResponse
-          >(this.chargingStation, RequestCommand.STATUS_NOTIFICATION, {
-            connectorId: requestPayload.connectorId,
-            errorCode: requestPayload.errorCode,
-            status: requestPayload.status,
-            ...(requestPayload.info && { info: requestPayload.info }),
-            ...(requestPayload.timestamp && { timestamp: requestPayload.timestamp }),
-            ...(requestPayload.vendorId && { vendorId: requestPayload.vendorId }),
-            ...(requestPayload.vendorErrorCode && {
-              vendorErrorCode: requestPayload.vendorErrorCode,
-            }),
-          }),
+          >(this.chargingStation, RequestCommand.STATUS_NOTIFICATION, requestPayload),
       ],
       [
         BroadcastChannelProcedureName.HEARTBEAT,
-        async (requestPayload?: BroadcastChannelRequestPayload) => {
-          delete requestPayload.hashId;
-          delete requestPayload.hashIds;
-          delete requestPayload.connectorIds;
-          return this.chargingStation.ocppRequestService.requestHandler<
+        async (requestPayload?: BroadcastChannelRequestPayload) =>
+          this.chargingStation.ocppRequestService.requestHandler<
             HeartbeatRequest,
             HeartbeatResponse
-          >(this.chargingStation, RequestCommand.HEARTBEAT, requestPayload);
+          >(this.chargingStation, RequestCommand.HEARTBEAT, requestPayload),
+      ],
+      [
+        BroadcastChannelProcedureName.METER_VALUES,
+        async (requestPayload?: BroadcastChannelRequestPayload) => {
+          const configuredMeterValueSampleInterval =
+            ChargingStationConfigurationUtils.getConfigurationKey(
+              chargingStation,
+              StandardParametersKey.MeterValueSampleInterval
+            );
+          return this.chargingStation.ocppRequestService.requestHandler<
+            MeterValuesRequest,
+            MeterValuesResponse
+          >(this.chargingStation, RequestCommand.METER_VALUES, {
+            ...requestPayload,
+            meterValue: requestPayload.meterValue ?? [
+              OCPP16ServiceUtils.buildMeterValue(
+                this.chargingStation,
+                requestPayload.connectorId,
+                this.chargingStation.getConnectorStatus(requestPayload.connectorId)?.transactionId,
+                configuredMeterValueSampleInterval
+                  ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000
+                  : Constants.DEFAULT_METER_VALUES_INTERVAL
+              ),
+            ],
+          });
         },
       ],
     ]);
@@ -153,7 +184,6 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
       );
       return;
     }
-
     let responsePayload: BroadcastChannelResponsePayload;
     let commandResponse: CommandResponse | void;
     try {
@@ -164,10 +194,11 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
           status: ResponseStatus.SUCCESS,
         };
       } else {
-        responsePayload = {
-          hashId: this.chargingStation.stationInfo.hashId,
-          status: this.commandResponseToResponseStatus(command, commandResponse as CommandResponse),
-        };
+        responsePayload = this.commandResponseToResponsePayload(
+          command,
+          requestPayload,
+          commandResponse as CommandResponse
+        );
       }
     } catch (error) {
       logger.error(
@@ -184,8 +215,9 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
         errorStack: (error as Error).stack,
         errorDetails: (error as OCPPError).details,
       };
+    } finally {
+      this.sendResponse([uuid, responsePayload]);
     }
-    this.sendResponse([uuid, responsePayload]);
   }
 
   private messageErrorHandler(messageEvent: MessageEvent): void {
@@ -200,11 +232,45 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
     requestPayload: BroadcastChannelRequestPayload
   ): Promise<CommandResponse | void> {
     if (this.commandHandlers.has(command) === true) {
+      this.cleanRequestPayload(command, requestPayload);
       return this.commandHandlers.get(command)(requestPayload);
     }
     throw new BaseError(`Unknown worker broadcast channel command: ${command}`);
   }
 
+  private cleanRequestPayload(
+    command: BroadcastChannelProcedureName,
+    requestPayload: BroadcastChannelRequestPayload
+  ): void {
+    delete requestPayload.hashId;
+    delete requestPayload.hashIds;
+    [
+      BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
+      BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
+    ].includes(command) === false && delete requestPayload.connectorIds;
+  }
+
+  private commandResponseToResponsePayload(
+    command: BroadcastChannelProcedureName,
+    requestPayload: BroadcastChannelRequestPayload,
+    commandResponse: CommandResponse
+  ): BroadcastChannelResponsePayload {
+    const responseStatus = this.commandResponseToResponseStatus(command, commandResponse);
+    if (responseStatus === ResponseStatus.SUCCESS) {
+      return {
+        hashId: this.chargingStation.stationInfo.hashId,
+        status: responseStatus,
+      };
+    }
+    return {
+      hashId: this.chargingStation.stationInfo.hashId,
+      status: responseStatus,
+      command,
+      requestPayload,
+      commandResponse,
+    };
+  }
+
   private commandResponseToResponseStatus(
     command: BroadcastChannelProcedureName,
     commandResponse: CommandResponse
@@ -212,14 +278,20 @@ export default class ChargingStationWorkerBroadcastChannel extends WorkerBroadca
     switch (command) {
       case BroadcastChannelProcedureName.START_TRANSACTION:
       case BroadcastChannelProcedureName.STOP_TRANSACTION:
+      case BroadcastChannelProcedureName.AUTHORIZE:
         if (
-          (commandResponse as StartTransactionResponse | StopTransactionResponse)?.idTagInfo
-            ?.status === AuthorizationStatus.ACCEPTED
+          (
+            commandResponse as
+              | StartTransactionResponse
+              | StopTransactionResponse
+              | AuthorizeResponse
+          )?.idTagInfo?.status === AuthorizationStatus.ACCEPTED
         ) {
           return ResponseStatus.SUCCESS;
         }
         return ResponseStatus.FAILURE;
       case BroadcastChannelProcedureName.STATUS_NOTIFICATION:
+      case BroadcastChannelProcedureName.METER_VALUES:
         if (Utils.isEmptyObject(commandResponse) === true) {
           return ResponseStatus.SUCCESS;
         }