type GetConfigurationResponse,
type GetDiagnosticsRequest,
type GetDiagnosticsResponse,
+ type IncomingRequestCommand,
type IncomingRequestHandler,
type JsonType,
type LogConfiguration,
convertToInt,
formatDurationMilliSeconds,
handleIncomingRequestError,
- isAsyncFunction,
isEmpty,
isNotEmptyArray,
isNotEmptyString,
*/
export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
+ protected readonly csmsName = 'central system'
+
+ protected readonly incomingRequestHandlers: Map<IncomingRequestCommand, IncomingRequestHandler>
+
protected payloadValidatorFunctions: Map<OCPP16IncomingRequestCommand, ValidateFunction<JsonType>>
- private readonly incomingRequestHandlers: Map<
- OCPP16IncomingRequestCommand,
- IncomingRequestHandler
- >
+ protected readonly pendingStateBlockedCommands: IncomingRequestCommand[] = [
+ OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+ OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+ ]
public constructor () {
super(OCPPVersion.VERSION_16)
- this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
+ this.incomingRequestHandlers = new Map<IncomingRequestCommand, IncomingRequestHandler>([
[
OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
this.handleRequestCancelReservation.bind(this) as unknown as IncomingRequestHandler,
)
}
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- public async incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
+ public override stop (chargingStation: ChargingStation): void {
+ /* no-op for OCPP 1.6 */
+ }
+
+ protected isIncomingRequestCommandSupported (
chargingStation: ChargingStation,
- messageId: string,
- commandName: OCPP16IncomingRequestCommand,
- commandPayload: ReqType
- ): Promise<void> {
- let response: ResType
- if (
- chargingStation.stationInfo?.ocppStrictCompliance === true &&
- chargingStation.inPendingState() &&
- (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 system`,
- commandName,
- commandPayload
- )
- }
- if (
- chargingStation.inAcceptedState() ||
- chargingStation.inPendingState() ||
- (chargingStation.stationInfo?.ocppStrictCompliance === false &&
- chargingStation.inUnknownState())
- ) {
- if (
- this.incomingRequestHandlers.has(commandName) &&
- OCPP16ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName)
- ) {
- try {
- this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
- // Call the method to build the response
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)!
- if (isAsyncFunction(incomingRequestHandler)) {
- response = (await incomingRequestHandler(chargingStation, commandPayload)) as ResType
- } else {
- response = incomingRequestHandler(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
- )
- }
- } else {
- throw new OCPPError(
- ErrorType.SECURITY_ERROR,
- `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
- commandPayload,
- undefined,
- 2
- )} while the charging station is not registered on the central system`,
- commandName,
- commandPayload
- )
- }
- // Send the built response
- await chargingStation.ocppRequestService.sendResponse(
+ commandName: IncomingRequestCommand
+ ): boolean {
+ return OCPP16ServiceUtils.isIncomingRequestCommandSupported(
chargingStation,
- messageId,
- response,
- commandName
+ commandName as OCPP16IncomingRequestCommand
)
- // Emit command name event to allow delayed handling only if there are listeners
- if (this.listenerCount(commandName) > 0) {
- this.emit(commandName, chargingStation, commandPayload, response)
- }
- }
-
- public override stop (chargingStation: ChargingStation): void {
- /* no-op for OCPP 1.6 */
}
private composeCompositeSchedule (
hasReservationExpired,
resetConnectorStatus,
} from '../../../charging-station/index.js'
-import { OCPPError } from '../../../exception/index.js'
import {
ChargingStationEvents,
- ErrorType,
type JsonType,
OCPP16AuthorizationStatus,
type OCPP16AuthorizeRequest,
type OCPP16StopTransactionResponse,
OCPPVersion,
RegistrationStatusEnumType,
+ type RequestCommand,
ReservationTerminationReason,
type ResponseHandler,
} from '../../../types/index.js'
-import { Constants, convertToInt, isAsyncFunction, logger } from '../../../utils/index.js'
+import { Constants, convertToInt, logger } from '../../../utils/index.js'
import { OCPPResponseService } from '../OCPPResponseService.js'
import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js'
ValidateFunction<JsonType>
>
+ protected readonly bootNotificationRequestCommand = OCPP16RequestCommand.BOOT_NOTIFICATION
+ protected readonly csmsName = 'central system'
+
protected payloadValidatorFunctions: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
- private readonly responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>
+
+ protected readonly responseHandlers: Map<RequestCommand, ResponseHandler>
public constructor () {
super(OCPPVersion.VERSION_16)
- this.responseHandlers = new Map<OCPP16RequestCommand, ResponseHandler>([
+ this.responseHandlers = new Map<RequestCommand, ResponseHandler>([
[OCPP16RequestCommand.AUTHORIZE, this.handleResponseAuthorize.bind(this) as ResponseHandler],
[
OCPP16RequestCommand.BOOT_NOTIFICATION,
)
}
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- public async responseHandler<ReqType extends JsonType, ResType extends JsonType>(
+ protected isRequestCommandSupported (
chargingStation: ChargingStation,
- commandName: OCPP16RequestCommand,
- payload: ResType,
- requestPayload: ReqType
- ): Promise<void> {
- if (
- chargingStation.inAcceptedState() ||
- ((chargingStation.inUnknownState() || chargingStation.inPendingState()) &&
- commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) ||
- (chargingStation.stationInfo?.ocppStrictCompliance === false &&
- (chargingStation.inUnknownState() || chargingStation.inPendingState()))
- ) {
- if (
- this.responseHandlers.has(commandName) &&
- OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName)
- ) {
- try {
- this.validateResponsePayload(chargingStation, commandName, payload)
- logger.debug(
- `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handling '${commandName}' response`
- )
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const responseHandler = this.responseHandlers.get(commandName)!
- if (isAsyncFunction(responseHandler)) {
- await responseHandler(chargingStation, payload, requestPayload)
- } else {
- ;(
- responseHandler as (
- chargingStation: ChargingStation,
- payload: JsonType,
- requestPayload?: JsonType
- ) => void
- )(chargingStation, payload, requestPayload)
- }
- logger.debug(
- `${chargingStation.logPrefix()} ${moduleName}.responseHandler: '${commandName}' response processed successfully`
- )
- } catch (error) {
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle '${commandName}' response error:`,
- error
- )
- throw error
- }
- } else {
- // Throw exception
- throw new OCPPError(
- ErrorType.NOT_IMPLEMENTED,
- `${commandName} is not implemented to handle response PDU ${JSON.stringify(
- payload,
- undefined,
- 2
- )}`,
- commandName,
- payload
- )
- }
- } else {
- throw new OCPPError(
- ErrorType.SECURITY_ERROR,
- `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
- payload,
- undefined,
- 2
- )} while the charging station is not registered on the central system`,
- commandName,
- payload
- )
- }
+ commandName: RequestCommand
+ ): boolean {
+ return OCPP16ServiceUtils.isRequestCommandSupported(
+ chargingStation,
+ commandName as OCPP16RequestCommand
+ )
}
private handleResponseAuthorize (
GetCertificateIdUseEnumType,
GetInstalledCertificateStatusEnumType,
GetVariableStatusEnumType,
+ type IncomingRequestCommand,
type IncomingRequestHandler,
InstallCertificateStatusEnumType,
InstallCertificateUseEnumType,
OCPP20ChargingRateUnitEnumType,
OCPP20ReasonEnumType,
} from '../../../types/ocpp/2.0/Transaction.js'
-import {
- Constants,
- generateUUID,
- isAsyncFunction,
- logger,
- sleep,
- validateUUID,
-} from '../../../utils/index.js'
+import { Constants, generateUUID, logger, sleep, validateUUID } from '../../../utils/index.js'
import { getConfigurationKey } from '../../ConfigurationKeyUtils.js'
import {
getIdTagsFile,
}
export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
+ protected readonly csmsName = 'CSMS'
+
+ protected readonly incomingRequestHandlers: Map<IncomingRequestCommand, IncomingRequestHandler>
+
protected payloadValidatorFunctions: Map<OCPP20IncomingRequestCommand, ValidateFunction<JsonType>>
- private readonly incomingRequestHandlers: Map<
- OCPP20IncomingRequestCommand,
- IncomingRequestHandler
- >
+ protected readonly pendingStateBlockedCommands: IncomingRequestCommand[] = [
+ OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION,
+ OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION,
+ ]
private readonly stationStates = new WeakMap<ChargingStation, OCPP20PerStationState>()
public constructor () {
super(OCPPVersion.VERSION_201)
- this.incomingRequestHandlers = new Map<OCPP20IncomingRequestCommand, IncomingRequestHandler>([
+ this.incomingRequestHandlers = new Map<IncomingRequestCommand, IncomingRequestHandler>([
[
OCPP20IncomingRequestCommand.CERTIFICATE_SIGNED,
this.toHandler(this.handleRequestCertificateSigned.bind(this)),
return setVariablesResponse
}
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- public async incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
- chargingStation: ChargingStation,
- messageId: string,
- commandName: OCPP20IncomingRequestCommand,
- commandPayload: ReqType
- ): Promise<void> {
- let response: ResType
- if (
- chargingStation.stationInfo?.ocppStrictCompliance === true &&
- chargingStation.inPendingState() &&
- (commandName === OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION ||
- commandName === OCPP20IncomingRequestCommand.REQUEST_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 CSMS`,
- commandName,
- commandPayload
- )
- }
- if (
- chargingStation.inAcceptedState() ||
- chargingStation.inPendingState() ||
- (chargingStation.stationInfo?.ocppStrictCompliance === false &&
- chargingStation.inUnknownState())
- ) {
- if (
- this.incomingRequestHandlers.has(commandName) &&
- OCPP20ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName)
- ) {
- try {
- this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)!
- if (isAsyncFunction(incomingRequestHandler)) {
- response = (await incomingRequestHandler(chargingStation, commandPayload)) as ResType
- } else {
- response = incomingRequestHandler(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
- )
- }
- } else {
- throw new OCPPError(
- ErrorType.SECURITY_ERROR,
- `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
- commandPayload,
- undefined,
- 2
- )} while the charging station is not registered on the CSMS`,
- commandName,
- commandPayload
- )
- }
- // Send the built response
- await chargingStation.ocppRequestService.sendResponse(
- chargingStation,
- messageId,
- response,
- commandName
- )
- // Emit command name event to allow delayed handling only if there are listeners
- if (this.listenerCount(commandName) > 0) {
- this.emit(commandName, chargingStation, commandPayload, response)
- }
- }
-
public override stop (chargingStation: ChargingStation): void {
const ss = this.stationStates.get(chargingStation)
if (ss != null) {
}
}
+ protected isIncomingRequestCommandSupported (
+ chargingStation: ChargingStation,
+ commandName: IncomingRequestCommand
+ ): boolean {
+ return OCPP20ServiceUtils.isIncomingRequestCommandSupported(
+ chargingStation,
+ commandName as OCPP20IncomingRequestCommand
+ )
+ }
+
private buildReportData (
chargingStation: ChargingStation,
reportBase: ReportBaseEnumType
import type { ValidateFunction } from 'ajv'
import { addConfigurationKey, type ChargingStation } from '../../../charging-station/index.js'
-import { OCPPError } from '../../../exception/index.js'
import {
ChargingStationEvents,
- ErrorType,
type JsonType,
type OCPP20BootNotificationResponse,
type OCPP20FirmwareStatusNotificationResponse,
type OCPP20TransactionEventResponse,
OCPPVersion,
RegistrationStatusEnumType,
+ type RequestCommand,
type ResponseHandler,
} from '../../../types/index.js'
import { OCPP20AuthorizationStatusEnumType } from '../../../types/ocpp/2.0/Transaction.js'
-import { isAsyncFunction, logger } from '../../../utils/index.js'
+import { logger } from '../../../utils/index.js'
import { OCPPResponseService } from '../OCPPResponseService.js'
import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
ValidateFunction<JsonType>
>
+ protected readonly bootNotificationRequestCommand = OCPP20RequestCommand.BOOT_NOTIFICATION
+ protected readonly csmsName = 'CSMS'
+
protected payloadValidatorFunctions: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
- private readonly responseHandlers: Map<OCPP20RequestCommand, ResponseHandler>
+
+ protected readonly responseHandlers: Map<RequestCommand, ResponseHandler>
public constructor () {
super(OCPPVersion.VERSION_201)
- this.responseHandlers = new Map<OCPP20RequestCommand, ResponseHandler>([
+ this.responseHandlers = new Map<RequestCommand, ResponseHandler>([
[
OCPP20RequestCommand.BOOT_NOTIFICATION,
this.handleResponseBootNotification.bind(this) as ResponseHandler,
)
}
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- public async responseHandler<ReqType extends JsonType, ResType extends JsonType>(
+ protected isRequestCommandSupported (
chargingStation: ChargingStation,
- commandName: OCPP20RequestCommand,
- payload: ResType,
- requestPayload: ReqType
- ): Promise<void> {
- if (
- chargingStation.inAcceptedState() ||
- ((chargingStation.inUnknownState() || chargingStation.inPendingState()) &&
- commandName === OCPP20RequestCommand.BOOT_NOTIFICATION) ||
- (chargingStation.stationInfo?.ocppStrictCompliance === false &&
- (chargingStation.inUnknownState() || chargingStation.inPendingState()))
- ) {
- if (
- this.responseHandlers.has(commandName) &&
- OCPP20ServiceUtils.isRequestCommandSupported(chargingStation, commandName)
- ) {
- try {
- this.validateResponsePayload(chargingStation, commandName, payload)
- logger.debug(
- `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handling '${commandName}' response`
- )
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const responseHandler = this.responseHandlers.get(commandName)!
- if (isAsyncFunction(responseHandler)) {
- await responseHandler(chargingStation, payload, requestPayload)
- } else {
- ;(
- responseHandler as (
- chargingStation: ChargingStation,
- payload: JsonType,
- requestPayload?: JsonType
- ) => void
- )(chargingStation, payload, requestPayload)
- }
- logger.debug(
- `${chargingStation.logPrefix()} ${moduleName}.responseHandler: '${commandName}' response processed successfully`
- )
- } catch (error) {
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle '${commandName}' response error:`,
- error
- )
- throw error
- }
- } else {
- // Throw exception
- throw new OCPPError(
- ErrorType.NOT_IMPLEMENTED,
- `${commandName} is not implemented to handle response PDU ${JSON.stringify(
- payload,
- undefined,
- 2
- )}`,
- commandName,
- payload
- )
- }
- } else {
- throw new OCPPError(
- ErrorType.SECURITY_ERROR,
- `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
- payload,
- undefined,
- 2
- )} while the charging station is not registered on the CSMS`,
- commandName,
- payload
- )
- }
+ commandName: RequestCommand
+ ): boolean {
+ return OCPP20ServiceUtils.isRequestCommandSupported(
+ chargingStation,
+ commandName as OCPP20RequestCommand
+ )
}
private handleResponseBootNotification (
import _ajvFormats from 'ajv-formats'
import { EventEmitter } from 'node:events'
-import type { IncomingRequestCommand, JsonType, OCPPVersion } from '../../types/index.js'
-
import { type ChargingStation } from '../../charging-station/index.js'
import { OCPPError } from '../../exception/index.js'
-import { logger } from '../../utils/index.js'
+import {
+ ErrorType,
+ type IncomingRequestCommand,
+ type IncomingRequestHandler,
+ type JsonType,
+ type OCPPVersion,
+} from '../../types/index.js'
+import { isAsyncFunction, logger } from '../../utils/index.js'
import { ajvErrorsToErrorType } from './OCPPServiceUtils.js'
type Ajv = _Ajv.default
>()
protected readonly ajv: Ajv
+ protected abstract readonly csmsName: string
+ protected abstract readonly incomingRequestHandlers: Map<
+ IncomingRequestCommand,
+ IncomingRequestHandler
+ >
+
protected abstract payloadValidatorFunctions: Map<
IncomingRequestCommand,
ValidateFunction<JsonType>
>
+ protected abstract readonly pendingStateBlockedCommands: IncomingRequestCommand[]
private readonly version: OCPPVersion
protected constructor (version: OCPPVersion) {
return OCPPIncomingRequestService.instances.get(this) as T
}
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-unnecessary-type-parameters
- public abstract incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
+ public async incomingRequestHandler<ReqType extends JsonType, ResType extends JsonType>(
chargingStation: ChargingStation,
messageId: string,
commandName: IncomingRequestCommand,
commandPayload: ReqType
- ): Promise<void>
+ ): Promise<void> {
+ let response: ResType
+ if (
+ chargingStation.stationInfo?.ocppStrictCompliance === true &&
+ chargingStation.inPendingState() &&
+ this.pendingStateBlockedCommands.includes(commandName)
+ ) {
+ 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 ${this.csmsName}`,
+ commandName,
+ commandPayload
+ )
+ }
+ if (
+ chargingStation.inAcceptedState() ||
+ chargingStation.inPendingState() ||
+ (chargingStation.stationInfo?.ocppStrictCompliance === false &&
+ chargingStation.inUnknownState())
+ ) {
+ if (
+ this.incomingRequestHandlers.has(commandName) &&
+ this.isIncomingRequestCommandSupported(chargingStation, commandName)
+ ) {
+ try {
+ this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)!
+ if (isAsyncFunction(incomingRequestHandler)) {
+ response = (await incomingRequestHandler(chargingStation, commandPayload)) as ResType
+ } else {
+ response = incomingRequestHandler(chargingStation, commandPayload) as ResType
+ }
+ } catch (error) {
+ // Log
+ logger.error(
+ `${chargingStation.logPrefix()} ${this.constructor.name}.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
+ )
+ }
+ } else {
+ throw new OCPPError(
+ ErrorType.SECURITY_ERROR,
+ `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
+ commandPayload,
+ undefined,
+ 2
+ )} while the charging station is not registered on the ${this.csmsName}`,
+ commandName,
+ commandPayload
+ )
+ }
+ // Send the built response
+ await chargingStation.ocppRequestService.sendResponse(
+ chargingStation,
+ messageId,
+ response,
+ commandName
+ )
+ // Emit command name event to allow delayed handling only if there are listeners
+ if (this.listenerCount(commandName) > 0) {
+ this.emit(commandName, chargingStation, commandPayload, response)
+ }
+ }
public abstract stop (chargingStation: ChargingStation): void
+
+ protected abstract isIncomingRequestCommandSupported (
+ chargingStation: ChargingStation,
+ commandName: IncomingRequestCommand
+ ): boolean
/**
* Validates incoming request payload against JSON schema
* @param chargingStation - The charging station instance processing the request
import _ajvFormats from 'ajv-formats'
import type { ChargingStation } from '../../charging-station/index.js'
-import type {
- IncomingRequestCommand,
- JsonType,
- OCPPVersion,
- RequestCommand,
-} from '../../types/index.js'
import { OCPPError } from '../../exception/index.js'
-import { Constants, logger } from '../../utils/index.js'
+import {
+ ErrorType,
+ type IncomingRequestCommand,
+ type JsonType,
+ type OCPPVersion,
+ type RequestCommand,
+ type ResponseHandler,
+} from '../../types/index.js'
+import { Constants, isAsyncFunction, logger } from '../../utils/index.js'
import { ajvErrorsToErrorType } from './OCPPServiceUtils.js'
type Ajv = _Ajv.default
protected readonly ajv: Ajv
protected readonly ajvIncomingRequest: Ajv
+ protected abstract readonly bootNotificationRequestCommand: RequestCommand
+ protected abstract readonly csmsName: string
protected emptyResponseHandler = Constants.EMPTY_FUNCTION
protected abstract payloadValidatorFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
+ protected abstract readonly responseHandlers: Map<RequestCommand, ResponseHandler>
private readonly version: OCPPVersion
protected constructor (version: OCPPVersion) {
}
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
- public abstract responseHandler<ReqType extends JsonType, ResType extends JsonType>(
+ public async responseHandler<ReqType extends JsonType, ResType extends JsonType>(
chargingStation: ChargingStation,
commandName: RequestCommand,
payload: ResType,
requestPayload: ReqType
- ): Promise<void>
+ ): Promise<void> {
+ if (
+ chargingStation.inAcceptedState() ||
+ ((chargingStation.inUnknownState() || chargingStation.inPendingState()) &&
+ commandName === this.bootNotificationRequestCommand) ||
+ (chargingStation.stationInfo?.ocppStrictCompliance === false &&
+ (chargingStation.inUnknownState() || chargingStation.inPendingState()))
+ ) {
+ if (
+ this.responseHandlers.has(commandName) &&
+ this.isRequestCommandSupported(chargingStation, commandName)
+ ) {
+ try {
+ this.validateResponsePayload(chargingStation, commandName, payload)
+ logger.debug(
+ `${chargingStation.logPrefix()} ${this.constructor.name}.responseHandler: Handling '${commandName}' response`
+ )
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ const responseHandler = this.responseHandlers.get(commandName)!
+ if (isAsyncFunction(responseHandler)) {
+ await responseHandler(chargingStation, payload, requestPayload)
+ } else {
+ ;(
+ responseHandler as (
+ chargingStation: ChargingStation,
+ payload: JsonType,
+ requestPayload?: JsonType
+ ) => void
+ )(chargingStation, payload, requestPayload)
+ }
+ logger.debug(
+ `${chargingStation.logPrefix()} ${this.constructor.name}.responseHandler: '${commandName}' response processed successfully`
+ )
+ } catch (error) {
+ logger.error(
+ `${chargingStation.logPrefix()} ${this.constructor.name}.responseHandler: Handle '${commandName}' response error:`,
+ error
+ )
+ throw error
+ }
+ } else {
+ // Throw exception
+ throw new OCPPError(
+ ErrorType.NOT_IMPLEMENTED,
+ `${commandName} is not implemented to handle response PDU ${JSON.stringify(
+ payload,
+ undefined,
+ 2
+ )}`,
+ commandName,
+ payload
+ )
+ }
+ } else {
+ throw new OCPPError(
+ ErrorType.SECURITY_ERROR,
+ `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
+ payload,
+ undefined,
+ 2
+ )} while the charging station is not registered on the ${this.csmsName}`,
+ commandName,
+ payload
+ )
+ }
+ }
+
+ protected abstract isRequestCommandSupported (
+ chargingStation: ChargingStation,
+ commandName: RequestCommand
+ ): boolean
/**
* Validates incoming response payload against JSON schema