Fix OCPP message type definition and usage
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 17 Apr 2022 10:25:06 +0000 (12:25 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 17 Apr 2022 10:25:06 +0000 (12:25 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPResponseService.ts
src/exception/OCPPError.ts
src/types/ocpp/Requests.ts
src/types/ocpp/Responses.ts

index 1efcf5c4c3422d388079bfa4aeb0723436bfd245..d2d509f0386bb89472c2eb313490db780529f260 100644 (file)
@@ -14,9 +14,11 @@ import {
 } from '../types/ocpp/Requests';
 import {
   BootNotificationResponse,
+  ErrorResponse,
   HeartbeatResponse,
   MeterValuesResponse,
   RegistrationStatus,
+  Response,
   StatusNotificationResponse,
 } from '../types/ocpp/Responses';
 import {
@@ -1468,117 +1470,116 @@ export default class ChargingStation {
   }
 
   private async onMessage(data: Data): Promise<void> {
-    let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [
-      0,
-      '',
-      '' as IncomingRequestCommand,
-      {},
-      {},
-    ];
-    let responseCallback: (
-      payload: JsonType | string,
-      requestPayload: JsonType | OCPPError
-    ) => void;
+    let messageType: number;
+    let messageId: string;
+    let commandName: IncomingRequestCommand;
+    let commandPayload: JsonType;
+    let errorType: ErrorType;
+    let errorMessage: string;
+    let errorDetails: JsonType;
+    let responseCallback: (payload: JsonType, requestPayload: JsonType) => void;
     let rejectCallback: (error: OCPPError, requestStatistic?: boolean) => void;
     let requestCommandName: RequestCommand | IncomingRequestCommand;
-    let requestPayload: JsonType | OCPPError;
+    let requestPayload: JsonType;
     let cachedRequest: CachedRequest;
     let errMsg: string;
     try {
-      const request = JSON.parse(data.toString()) as IncomingRequest;
+      const request = JSON.parse(data.toString()) as IncomingRequest | Response | ErrorResponse;
       if (Utils.isIterable(request)) {
-        // Parse the message
-        [messageType, messageId, commandName, commandPayload, errorDetails] = request;
+        [messageType] = request;
+        // Check the type of message
+        switch (messageType) {
+          // Incoming Message
+          case MessageType.CALL_MESSAGE:
+            [, messageId, commandName, commandPayload] = request as IncomingRequest;
+            if (this.getEnableStatistics()) {
+              this.performanceStatistics.addRequestStatistic(commandName, messageType);
+            }
+            logger.debug(
+              `${this.logPrefix()} << Command '${commandName}' received request payload: ${JSON.stringify(
+                request
+              )}`
+            );
+            // Process the message
+            await this.ocppIncomingRequestService.incomingRequestHandler(
+              messageId,
+              commandName,
+              commandPayload
+            );
+            break;
+          // Outcome Message
+          case MessageType.CALL_RESULT_MESSAGE:
+            [, messageId, commandPayload] = request as Response;
+            // Respond
+            cachedRequest = this.requests.get(messageId);
+            if (Utils.isIterable(cachedRequest)) {
+              [responseCallback, , requestCommandName, requestPayload] = cachedRequest;
+            } else {
+              throw new OCPPError(
+                ErrorType.PROTOCOL_ERROR,
+                `Cached request for message id ${messageId} response is not iterable`,
+                requestCommandName
+              );
+            }
+            logger.debug(
+              `${this.logPrefix()} << Command '${requestCommandName}' received response payload: ${JSON.stringify(
+                request
+              )}`
+            );
+            if (!responseCallback) {
+              // Error
+              throw new OCPPError(
+                ErrorType.INTERNAL_ERROR,
+                `Response for unknown message id ${messageId}`,
+                requestCommandName
+              );
+            }
+            responseCallback(commandPayload, requestPayload);
+            break;
+          // Error Message
+          case MessageType.CALL_ERROR_MESSAGE:
+            [, messageId, errorType, errorMessage, errorDetails] = request as ErrorResponse;
+            cachedRequest = this.requests.get(messageId);
+            if (Utils.isIterable(cachedRequest)) {
+              [, rejectCallback, requestCommandName] = cachedRequest;
+            } else {
+              throw new OCPPError(
+                ErrorType.PROTOCOL_ERROR,
+                `Cached request for message id ${messageId} error response is not iterable`
+              );
+            }
+            logger.debug(
+              `${this.logPrefix()} << Command '${requestCommandName}' received error payload: ${JSON.stringify(
+                request
+              )}`
+            );
+            if (!rejectCallback) {
+              // Error
+              throw new OCPPError(
+                ErrorType.INTERNAL_ERROR,
+                `Error response for unknown message id ${messageId}`,
+                requestCommandName
+              );
+            }
+            rejectCallback(
+              new OCPPError(errorType, errorMessage, requestCommandName, errorDetails)
+            );
+            break;
+          // Error
+          default:
+            // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+            errMsg = `${this.logPrefix()} Wrong message type ${messageType}`;
+            logger.error(errMsg);
+            throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg);
+        }
       } else {
         throw new OCPPError(
           ErrorType.PROTOCOL_ERROR,
           'Incoming message is not iterable',
-          Utils.isString(commandName) && commandName,
+          Utils.isString(commandName) ? commandName : requestCommandName,
           { payload: request }
         );
       }
-      // Check the Type of message
-      switch (messageType) {
-        // Incoming Message
-        case MessageType.CALL_MESSAGE:
-          if (this.getEnableStatistics()) {
-            this.performanceStatistics.addRequestStatistic(commandName, messageType);
-          }
-          logger.debug(
-            `${this.logPrefix()} << Command '${commandName}' received request payload: ${JSON.stringify(
-              request
-            )}`
-          );
-          // Process the call
-          await this.ocppIncomingRequestService.incomingRequestHandler(
-            messageId,
-            commandName,
-            commandPayload
-          );
-          break;
-        // Outcome Message
-        case MessageType.CALL_RESULT_MESSAGE:
-          // Respond
-          cachedRequest = this.requests.get(messageId);
-          if (Utils.isIterable(cachedRequest)) {
-            [responseCallback, , requestCommandName, requestPayload] = cachedRequest;
-          } else {
-            throw new OCPPError(
-              ErrorType.PROTOCOL_ERROR,
-              `Cached request for message id ${messageId} response is not iterable`,
-              requestCommandName
-            );
-          }
-          logger.debug(
-            `${this.logPrefix()} << Command '${requestCommandName}' received response payload: ${JSON.stringify(
-              request
-            )}`
-          );
-          if (!responseCallback) {
-            // Error
-            throw new OCPPError(
-              ErrorType.INTERNAL_ERROR,
-              `Response for unknown message id ${messageId}`,
-              requestCommandName
-            );
-          }
-          responseCallback(commandName, requestPayload);
-          break;
-        // Error Message
-        case MessageType.CALL_ERROR_MESSAGE:
-          cachedRequest = this.requests.get(messageId);
-          if (Utils.isIterable(cachedRequest)) {
-            [, rejectCallback, requestCommandName] = cachedRequest;
-          } else {
-            throw new OCPPError(
-              ErrorType.PROTOCOL_ERROR,
-              `Cached request for message id ${messageId} error response is not iterable`
-            );
-          }
-          logger.debug(
-            `${this.logPrefix()} << Command '${requestCommandName}' received error payload: ${JSON.stringify(
-              request
-            )}`
-          );
-          if (!rejectCallback) {
-            // Error
-            throw new OCPPError(
-              ErrorType.INTERNAL_ERROR,
-              `Error response for unknown message id ${messageId}`,
-              requestCommandName
-            );
-          }
-          rejectCallback(
-            new OCPPError(commandName, commandPayload.toString(), requestCommandName, errorDetails)
-          );
-          break;
-        // Error
-        default:
-          // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
-          errMsg = `${this.logPrefix()} Wrong message type ${messageType}`;
-          logger.error(errMsg);
-          throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg);
-      }
     } catch (error) {
       // Log
       logger.error(
@@ -1590,7 +1591,11 @@ export default class ChargingStation {
       );
       // Send error
       messageType === MessageType.CALL_MESSAGE &&
-        (await this.ocppRequestService.sendError(messageId, error as OCPPError, commandName));
+        (await this.ocppRequestService.sendError(
+          messageId,
+          error as OCPPError,
+          Utils.isString(commandName) ? commandName : requestCommandName
+        ));
     }
   }
 
index c96cea3af7d1f85e1c0a2233c0d01043f07f5323..f2a08a1656b339f79ba5830b62cb2d96c575ace5 100644 (file)
@@ -60,7 +60,7 @@ export default class OCPP16ResponseService extends OCPPResponseService {
 
   public async responseHandler(
     commandName: OCPP16RequestCommand,
-    payload: JsonType | string,
+    payload: JsonType,
     requestPayload: JsonType
   ): Promise<void> {
     if (
index ef1e4749d56151d05eafd7ed438236018d8fcec1..704838e960c0638eeef967f3480a303bca78f9c3 100644 (file)
@@ -1,5 +1,7 @@
+import { ErrorResponse, Response } from '../../types/ocpp/Responses';
 import {
   IncomingRequestCommand,
+  OutgoingRequest,
   RequestCommand,
   RequestParams,
   ResponseType,
@@ -73,7 +75,7 @@ export default abstract class OCPPRequestService {
   public async sendError(
     messageId: string,
     ocppError: OCPPError,
-    commandName: IncomingRequestCommand
+    commandName: RequestCommand | IncomingRequestCommand
   ): Promise<ResponseType> {
     try {
       // Send error message
@@ -199,7 +201,7 @@ export default abstract class OCPPRequestService {
            * @param requestPayload
            */
           async function responseCallback(
-            payload: JsonType | string,
+            payload: JsonType,
             requestPayload: JsonType
           ): Promise<void> {
             if (self.chargingStation.getEnableStatistics()) {
@@ -271,7 +273,7 @@ export default abstract class OCPPRequestService {
     messagePayload: JsonType | OCPPError,
     messageType: MessageType,
     commandName?: RequestCommand | IncomingRequestCommand,
-    responseCallback?: (payload: JsonType | string, requestPayload: JsonType) => Promise<void>,
+    responseCallback?: (payload: JsonType, requestPayload: JsonType) => Promise<void>,
     rejectCallback?: (error: OCPPError, requestStatistic?: boolean) => void
   ): string {
     let messageToSend: string;
@@ -284,14 +286,19 @@ export default abstract class OCPPRequestService {
           responseCallback,
           rejectCallback,
           commandName,
-          messagePayload,
+          messagePayload as JsonType,
         ]);
-        messageToSend = JSON.stringify([messageType, messageId, commandName, messagePayload]);
+        messageToSend = JSON.stringify([
+          messageType,
+          messageId,
+          commandName,
+          messagePayload,
+        ] as OutgoingRequest);
         break;
       // Response
       case MessageType.CALL_RESULT_MESSAGE:
         // Build response
-        messageToSend = JSON.stringify([messageType, messageId, messagePayload]);
+        messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response);
         break;
       // Error Message
       case MessageType.CALL_ERROR_MESSAGE:
@@ -299,10 +306,10 @@ export default abstract class OCPPRequestService {
         messageToSend = JSON.stringify([
           messageType,
           messageId,
-          messagePayload?.code ?? ErrorType.GENERIC_ERROR,
-          messagePayload?.message ?? '',
-          messagePayload?.details ?? { commandName },
-        ]);
+          (messagePayload as OCPPError)?.code ?? ErrorType.GENERIC_ERROR,
+          (messagePayload as OCPPError)?.message ?? '',
+          (messagePayload as OCPPError)?.details ?? { commandName },
+        ] as ErrorResponse);
         break;
     }
     return messageToSend;
index cfb1aa08f45e75a42e88c31295daa0ad6b1389e4..e838bd9fb1d4ae2280ca08d2e9516917ffac37fc 100644 (file)
@@ -26,7 +26,7 @@ export default abstract class OCPPResponseService {
 
   public abstract responseHandler(
     commandName: RequestCommand,
-    payload: JsonType | string,
+    payload: JsonType,
     requestPayload: JsonType
   ): Promise<void>;
 }
index 9f2b22623dc65085fac88b4c9191d3a3c86e9061..e67f3c95f56c38b81a22e1c70a1be191199e610c 100644 (file)
@@ -7,12 +7,12 @@ import { ErrorType } from '../types/ocpp/ErrorType';
 import { JsonType } from '../types/JsonType';
 
 export default class OCPPError extends BaseError {
-  code: ErrorType | IncomingRequestCommand;
+  code: ErrorType;
   command?: RequestCommand | IncomingRequestCommand;
   details?: JsonType;
 
   constructor(
-    code: ErrorType | IncomingRequestCommand,
+    code: ErrorType,
     message: string,
     command?: RequestCommand | IncomingRequestCommand,
     details?: JsonType
index 1683654c73cc13c9bb22c473c067f2cead27c46c..16a79c05d2cf74365cd09f2e102af269cfe08b0a 100644 (file)
@@ -13,15 +13,26 @@ import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus';
 import { OCPP16MeterValuesRequest } from './1.6/MeterValues';
 import OCPPError from '../../exception/OCPPError';
 
+export type OutgoingRequest = [MessageType.CALL_MESSAGE, string, RequestCommand, JsonType];
+
+export type IncomingRequest = [MessageType.CALL_MESSAGE, string, IncomingRequestCommand, JsonType];
+
+export type CachedRequest = [
+  (payload: JsonType, requestPayload: JsonType) => void,
+  (error: OCPPError, requestStatistic?: boolean) => void,
+  RequestCommand | IncomingRequestCommand,
+  JsonType
+];
+
+export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise<JsonType>;
+
+export type ResponseType = JsonType | OCPPError;
+
 export interface RequestParams {
   skipBufferingOnError?: boolean;
   triggerMessage?: boolean;
 }
 
-export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise<JsonType>;
-
-export type ResponseType = JsonType | OCPPError | string;
-
 export type BootNotificationRequest = OCPP16BootNotificationRequest;
 
 export type HeartbeatRequest = OCPP16HeartbeatRequest;
@@ -53,14 +64,3 @@ export type DiagnosticsStatus = OCPP16DiagnosticsStatus;
 export const DiagnosticsStatus = {
   ...OCPP16DiagnosticsStatus,
 };
-
-export type Request = [MessageType, string, RequestCommand, JsonType, JsonType];
-
-export type IncomingRequest = [MessageType, string, IncomingRequestCommand, JsonType, JsonType];
-
-export type CachedRequest = [
-  (payload: JsonType, requestPayload: JsonType) => void,
-  (error: OCPPError, requestStatistic?: boolean) => void,
-  RequestCommand | IncomingRequestCommand,
-  JsonType | OCPPError
-];
index d7e6db554f68456e79aac01709f4366b6bbaeb64..baefc637ba389df281b8136323137b6312891451 100644 (file)
@@ -11,11 +11,17 @@ import {
   OCPP16UnlockStatus,
 } from './1.6/Responses';
 
+import { ErrorType } from './ErrorType';
 import { JsonType } from '../JsonType';
+import { MessageType } from './MessageType';
 import { OCPP16MeterValuesResponse } from './1.6/MeterValues';
 
+export type Response = [MessageType.CALL_RESULT_MESSAGE, string, JsonType];
+
+export type ErrorResponse = [MessageType.CALL_ERROR_MESSAGE, string, ErrorType, string, JsonType];
+
 export type ResponseHandler = (
-  payload: JsonType | string,
+  payload: JsonType,
   requestPayload?: JsonType
 ) => void | Promise<void>;