Skip to content
This repository has been archived by the owner on Jun 12, 2024. It is now read-only.

Commit

Permalink
Fix OCPP message type definition and usage
Browse files Browse the repository at this point in the history
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
  • Loading branch information
Jérôme Benoit committed Apr 17, 2022
1 parent 7f81816 commit b3ec7bc
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 129 deletions.
203 changes: 104 additions & 99 deletions src/charging-station/ChargingStation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import {
} from '../types/ocpp/Requests';
import {
BootNotificationResponse,
ErrorResponse,
HeartbeatResponse,
MeterValuesResponse,
RegistrationStatus,
Response,
StatusNotificationResponse,
} from '../types/ocpp/Responses';
import {
Expand Down Expand Up @@ -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(
Expand All @@ -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
));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
27 changes: 17 additions & 10 deletions src/charging-station/ocpp/OCPPRequestService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ErrorResponse, Response } from '../../types/ocpp/Responses';
import {
IncomingRequestCommand,
OutgoingRequest,
RequestCommand,
RequestParams,
ResponseType,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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;
Expand All @@ -284,25 +286,30 @@ 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:
// Build Error Message
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;
Expand Down
2 changes: 1 addition & 1 deletion src/charging-station/ocpp/OCPPResponseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default abstract class OCPPResponseService {

public abstract responseHandler(
commandName: RequestCommand,
payload: JsonType | string,
payload: JsonType,
requestPayload: JsonType
): Promise<void>;
}
4 changes: 2 additions & 2 deletions src/exception/OCPPError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 15 additions & 15 deletions src/types/ocpp/Requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
];
Loading

0 comments on commit b3ec7bc

Please sign in to comment.