+import { OCPP16Constants } from './OCPP16Constants';
+import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
+import {
+ type ChargingStation,
+ canProceedChargingProfile,
+ checkChargingStation,
+ getConfigurationKey,
+ getConnectorChargingProfiles,
+ prepareChargingProfileKind,
+ removeExpiredReservations,
+ setConfigurationKeyValue,
+} from '../../../charging-station';
+import { OCPPError } from '../../../exception';
+import {
+ type ChangeConfigurationRequest,
+ type ChangeConfigurationResponse,
+ type ClearChargingProfileRequest,
+ type ClearChargingProfileResponse,
+ ErrorType,
+ type GenericResponse,
+ GenericStatus,
+ type GetConfigurationRequest,
+ type GetConfigurationResponse,
+ type GetDiagnosticsRequest,
+ type GetDiagnosticsResponse,
+ type IncomingRequestHandler,
+ type JsonType,
+ OCPP16AuthorizationStatus,
+ OCPP16AvailabilityType,
+ type OCPP16BootNotificationRequest,
+ type OCPP16BootNotificationResponse,
+ type OCPP16CancelReservationRequest,
+ type OCPP16ChangeAvailabilityRequest,
+ type OCPP16ChangeAvailabilityResponse,
+ OCPP16ChargePointErrorCode,
+ OCPP16ChargePointStatus,
+ type OCPP16ChargingProfile,
+ OCPP16ChargingProfilePurposeType,
+ type OCPP16ChargingSchedule,
+ type OCPP16ClearCacheRequest,
+ type OCPP16DataTransferRequest,
+ type OCPP16DataTransferResponse,
+ OCPP16DataTransferVendorId,
+ OCPP16DiagnosticsStatus,
+ type OCPP16DiagnosticsStatusNotificationRequest,
+ type OCPP16DiagnosticsStatusNotificationResponse,
+ OCPP16FirmwareStatus,
+ type OCPP16FirmwareStatusNotificationRequest,
+ type OCPP16FirmwareStatusNotificationResponse,
+ type OCPP16GetCompositeScheduleRequest,
+ type OCPP16GetCompositeScheduleResponse,
+ type OCPP16HeartbeatRequest,
+ type OCPP16HeartbeatResponse,
+ OCPP16IncomingRequestCommand,
+ OCPP16MessageTrigger,
+ OCPP16RequestCommand,
+ type OCPP16ReserveNowRequest,
+ type OCPP16ReserveNowResponse,
+ OCPP16StandardParametersKey,
+ type OCPP16StartTransactionRequest,
+ type OCPP16StartTransactionResponse,
+ type OCPP16StatusNotificationRequest,
+ type OCPP16StatusNotificationResponse,
+ OCPP16StopTransactionReason,
+ OCPP16SupportedFeatureProfiles,
+ type OCPP16TriggerMessageRequest,
+ type OCPP16TriggerMessageResponse,
+ type OCPP16UpdateFirmwareRequest,
+ type OCPP16UpdateFirmwareResponse,
+ type OCPPConfigurationKey,
+ OCPPVersion,
+ type RemoteStartTransactionRequest,
+ type RemoteStopTransactionRequest,
+ ReservationTerminationReason,
+ type ResetRequest,
+ type SetChargingProfileRequest,
+ type SetChargingProfileResponse,
+ type UnlockConnectorRequest,
+ type UnlockConnectorResponse,
+} from '../../../types';
+import {
+ Constants,
+ convertToDate,
+ convertToInt,
+ formatDurationMilliSeconds,
+ getRandomInteger,
+ isEmptyArray,
+ isNotEmptyArray,
+ isNotEmptyString,
+ isNullOrUndefined,
+ isUndefined,
+ logger,
+ sleep,
+} from '../../../utils';
+import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService';
+
+const moduleName = 'OCPP16IncomingRequestService';
+
+export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
+ protected jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonType>>;
+ private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
+
+ public constructor() {
+ // if (new.target?.name === moduleName) {
+ // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
+ // }
+ super(OCPPVersion.VERSION_16);
+ this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
+ [
+ OCPP16IncomingRequestCommand.RESET,
+ this.handleRequestReset.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.CLEAR_CACHE,
+ this.handleRequestClearCache.bind(this) as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
+ this.handleRequestUnlockConnector.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+ this.handleRequestGetConfiguration.bind(this) as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+ this.handleRequestChangeConfiguration.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
+ this.handleRequestGetCompositeSchedule.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+ this.handleRequestSetChargingProfile.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+ this.handleRequestClearChargingProfile.bind(this) as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+ this.handleRequestChangeAvailability.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+ this.handleRequestRemoteStartTransaction.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+ this.handleRequestRemoteStopTransaction.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+ this.handleRequestGetDiagnostics.bind(this) as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+ this.handleRequestTriggerMessage.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.DATA_TRANSFER,
+ this.handleRequestDataTransfer.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
+ this.handleRequestUpdateFirmware.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.RESERVE_NOW,
+ this.handleRequestReserveNow.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ [
+ OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
+ this.handleRequestCancelReservation.bind(this) as unknown as IncomingRequestHandler,
+ ],
+ ]);
+ this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonType>>([
+ [
+ OCPP16IncomingRequestCommand.RESET,
+ OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
+ 'assets/json-schemas/ocpp/1.6/Reset.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.CLEAR_CACHE,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
+ 'assets/json-schemas/ocpp/1.6/ClearCache.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
+ OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
+ 'assets/json-schemas/ocpp/1.6/UnlockConnector.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+ OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
+ 'assets/json-schemas/ocpp/1.6/GetConfiguration.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+ OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
+ 'assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+ OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
+ 'assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleRequest>(
+ 'assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+ OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
+ 'assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+ OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileRequest>(
+ 'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityRequest>(
+ 'assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+ OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
+ 'assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+ OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
+ 'assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
+ 'assets/json-schemas/ocpp/1.6/TriggerMessage.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.DATA_TRANSFER,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
+ 'assets/json-schemas/ocpp/1.6/DataTransfer.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
+ 'assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.RESERVE_NOW,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowRequest>(
+ 'assets/json-schemas/ocpp/1.6/ReserveNow.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ [
+ OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
+ OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16CancelReservationRequest>(
+ 'assets/json-schemas/ocpp/1.6/CancelReservation.json',
+ moduleName,
+ 'constructor',
+ ),
+ ],
+ ]);
+ this.validatePayload = this.validatePayload.bind(this) as (
+ chargingStation: ChargingStation,
+ commandName: OCPP16IncomingRequestCommand,
+ commandPayload: JsonType,
+ ) => boolean;
+ }
+
+ public async incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
+ chargingStation: ChargingStation,
+ messageId: string,
+ commandName: OCPP16IncomingRequestCommand,
+ commandPayload: ReqType,
+ ): Promise<void> {
+ let response: ResType;
+ if (
+ chargingStation.stationInfo?.ocppStrictCompliance === true &&
+ chargingStation.inPendingState() === true &&
+ (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION ||
+ commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)
+ ) {
+ throw new OCPPError(
+ ErrorType.SECURITY_ERROR,
+ `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
+ commandPayload,
+ undefined,
+ 2,
+ )} while the charging station is in pending state on the central server`,
+ commandName,
+ commandPayload,
+ );
+ }
+ if (
+ chargingStation.isRegistered() === true ||
+ (chargingStation.stationInfo?.ocppStrictCompliance === false &&
+ chargingStation.inUnknownState() === true)
+ ) {
+ if (
+ this.incomingRequestHandlers.has(commandName) === true &&
+ OCPP16ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName) === true
+ ) {
+ try {
+ this.validatePayload(chargingStation, commandName, commandPayload);
+ // Call the method to build the response
+ response = (await this.incomingRequestHandlers.get(commandName)!(
+ chargingStation,
+ commandPayload,
+ )) as ResType;
+ } catch (error) {
+ // Log
+ logger.error(
+ `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
+ error,
+ );
+ throw error;
+ }
+ } else {
+ // Throw exception
+ throw new OCPPError(
+ ErrorType.NOT_IMPLEMENTED,
+ `${commandName} is not implemented to handle request PDU ${JSON.stringify(
+ commandPayload,
+ undefined,
+ 2,
+ )}`,
+ commandName,
+ commandPayload,
+ );