]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: cleanup payload validation code
authorJérôme Benoit <jerome.benoit@sap.com>
Mon, 10 Nov 2025 14:30:23 +0000 (15:30 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Mon, 10 Nov 2025 14:30:23 +0000 (15:30 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
14 files changed:
src/charging-station/ChargingStation.ts
src/charging-station/Helpers.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/2.0/OCPP20ResponseService.ts
src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts
src/charging-station/ocpp/OCPPIncomingRequestService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPResponseService.ts
src/charging-station/ocpp/OCPPServiceUtils.ts

index 9569f9b1d81072887bb1638bde35d1b16706ac79..1ee68a9ab2d61351d00098e192b67be60a2b2d98 100644 (file)
@@ -421,24 +421,19 @@ export class ChargingStation extends EventEmitter {
   public getConnectorMaximumAvailablePower (connectorId: number): number {
     let connectorAmperageLimitationLimit: number | undefined
     const amperageLimitation = this.getAmperageLimitation()
-    if (
-      amperageLimitation != null &&
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      amperageLimitation < this.stationInfo!.maximumAmperage!
-    ) {
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    if (amperageLimitation != null && amperageLimitation < this.stationInfo!.maximumAmperage!) {
+      const voltageOut = this.getVoltageOut()
       connectorAmperageLimitationLimit =
         (this.stationInfo?.currentOutType === CurrentType.AC
           ? ACElectricUtils.powerTotal(
             this.getNumberOfPhases(),
-            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-            this.stationInfo.voltageOut!,
+            voltageOut,
             amperageLimitation *
                 (this.hasEvses ? this.getNumberOfEvses() : this.getNumberOfConnectors())
           )
           : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          DCElectricUtils.power(this.stationInfo!.voltageOut!, amperageLimitation)) /
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        this.powerDivider!
+          DCElectricUtils.power(voltageOut, amperageLimitation)) / this.powerDivider!
     }
     // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
     const connectorMaximumPower = this.stationInfo!.maximumPower! / this.powerDivider!
@@ -635,6 +630,14 @@ export class ChargingStation extends EventEmitter {
     }
   }
 
+  public getVoltageOut (stationInfo?: ChargingStationInfo): Voltage {
+    return (
+      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+      (stationInfo ?? this.stationInfo!).voltageOut ??
+      getDefaultVoltageOut(this.getCurrentOutType(stationInfo), this.logPrefix(), this.templateFile)
+    )
+  }
+
   public getWebSocketPingInterval (): number {
     return getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval) != null
       ? convertToInt(getConfigurationKey(this, StandardParametersKey.WebSocketPingInterval)?.value)
@@ -1471,14 +1474,6 @@ export class ChargingStation extends EventEmitter {
     return stationTemplate?.useConnectorId0 ?? Constants.DEFAULT_STATION_INFO.useConnectorId0!
   }
 
-  private getVoltageOut (stationInfo?: ChargingStationInfo): Voltage {
-    return (
-      // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      (stationInfo ?? this.stationInfo!).voltageOut ??
-      getDefaultVoltageOut(this.getCurrentOutType(stationInfo), this.logPrefix(), this.templateFile)
-    )
-  }
-
   private handleErrorMessage (errorResponse: ErrorResponse): void {
     const [messageType, messageId, errorType, errorMessage, errorDetails] = errorResponse
     if (!this.requests.has(messageId)) {
index c1edc53043c29ce01a43069be9475e6a7f46bbb6..bd3548792048be752f4a749bcf1d550db523a8ce 100644 (file)
@@ -810,15 +810,13 @@ const buildChargingProfilesLimit = (
         ? limit
         : ACElectricUtils.powerTotal(
           chargingStation.getNumberOfPhases(),
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-          chargingStation.stationInfo.voltageOut!,
+          chargingStation.getVoltageOut(),
           limit
         )
     case CurrentType.DC:
       return chargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
         ? limit
-        : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        DCElectricUtils.power(chargingStation.stationInfo.voltageOut!, limit)
+        : DCElectricUtils.power(chargingStation.getVoltageOut(), limit)
     default:
       logger.error(
         `${chargingStation.logPrefix()} ${moduleName}.buildChargingProfilesLimit: ${errorMsg}`
index b14ffbf538ca3bef4143ede4100985ef8a3e701d..2ace4b872be8bf08241251707c0595678981dcf6 100644 (file)
@@ -55,7 +55,6 @@ import {
   type OCPP16ChargingProfile,
   OCPP16ChargingProfilePurposeType,
   type OCPP16ChargingSchedule,
-  type OCPP16ClearCacheRequest,
   type OCPP16ClearChargingProfileRequest,
   type OCPP16ClearChargingProfileResponse,
   type OCPP16DataTransferRequest,
@@ -119,7 +118,7 @@ import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js'
 const moduleName = 'OCPP16IncomingRequestService'
 
 export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
-  protected payloadValidateFunctions: Map<OCPP16IncomingRequestCommand, ValidateFunction<JsonType>>
+  protected payloadValidatorFunctions: Map<OCPP16IncomingRequestCommand, ValidateFunction<JsonType>>
 
   private readonly incomingRequestHandlers: Map<
     OCPP16IncomingRequestCommand,
@@ -201,181 +200,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
         this.handleRequestUpdateFirmware.bind(this) as unknown as IncomingRequestHandler,
       ],
     ])
-    this.payloadValidateFunctions = new Map<
-      OCPP16IncomingRequestCommand,
-      ValidateFunction<JsonType>
-    >([
-      [
-        OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16CancelReservationRequest>(
-            'assets/json-schemas/ocpp/1.6/CancelReservation.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityRequest>(
-            'assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
-            'assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CLEAR_CACHE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
-            'assets/json-schemas/ocpp/1.6/ClearCache.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileRequest>(
-            'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.DATA_TRANSFER,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
-            'assets/json-schemas/ocpp/1.6/DataTransfer.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleRequest>(
-            'assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.GET_CONFIGURATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
-            'assets/json-schemas/ocpp/1.6/GetConfiguration.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
-            'assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
-            'assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
-            'assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.RESERVE_NOW,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowRequest>(
-            'assets/json-schemas/ocpp/1.6/ReserveNow.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.RESET,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
-            'assets/json-schemas/ocpp/1.6/Reset.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
-            'assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
-            'assets/json-schemas/ocpp/1.6/TriggerMessage.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
-            'assets/json-schemas/ocpp/1.6/UnlockConnector.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
-            'assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
+    this.payloadValidatorFunctions = OCPP16ServiceUtils.createPayloadValidatorMap(
+      OCPP16ServiceUtils.createIncomingRequestPayloadConfigs(),
+      OCPP16ServiceUtils.createIncomingRequestFactoryOptions(moduleName, 'constructor'),
+      this.ajv
+    )
     // Handle incoming request events
     this.on(
       OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
@@ -1781,7 +1610,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
     commandName: OCPP16IncomingRequestCommand,
     commandPayload: JsonType
   ): boolean {
-    if (this.payloadValidateFunctions.has(commandName)) {
+    if (this.payloadValidatorFunctions.has(commandName)) {
       return this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
     }
     logger.warn(
index 10505ff0c3a6634858c53eeb40d04a1efc11ddd3..cc63df8e55dbdacbc06bbb17aedecbf1dc8a4ea9 100644 (file)
@@ -10,19 +10,10 @@ import {
   ErrorType,
   type JsonObject,
   type JsonType,
-  type OCPP16AuthorizeRequest,
-  type OCPP16BootNotificationRequest,
   OCPP16ChargePointStatus,
-  type OCPP16DataTransferRequest,
-  type OCPP16DiagnosticsStatusNotificationRequest,
-  type OCPP16FirmwareStatusNotificationRequest,
-  type OCPP16HeartbeatRequest,
   type OCPP16MeterValue,
-  type OCPP16MeterValuesRequest,
   OCPP16RequestCommand,
   type OCPP16StartTransactionRequest,
-  type OCPP16StatusNotificationRequest,
-  type OCPP16StopTransactionRequest,
   OCPPVersion,
   type RequestParams,
 } from '../../../types/index.js'
@@ -34,115 +25,18 @@ import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js'
 const moduleName = 'OCPP16RequestService'
 
 export class OCPP16RequestService extends OCPPRequestService {
-  protected payloadValidateFunctions: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
+  protected payloadValidatorFunctions: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
 
   public constructor (ocppResponseService: OCPPResponseService) {
     // if (new.target.name === moduleName) {
     //   throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
     // }
     super(OCPPVersion.VERSION_16, ocppResponseService)
-    this.payloadValidateFunctions = new Map<OCPP16RequestCommand, ValidateFunction<JsonType>>([
-      [
-        OCPP16RequestCommand.AUTHORIZE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeRequest>(
-            'assets/json-schemas/ocpp/1.6/Authorize.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.BOOT_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationRequest>(
-            'assets/json-schemas/ocpp/1.6/BootNotification.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.DATA_TRANSFER,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
-            'assets/json-schemas/ocpp/1.6/DataTransfer.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationRequest>(
-            'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationRequest>(
-            'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.HEARTBEAT,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatRequest>(
-            'assets/json-schemas/ocpp/1.6/Heartbeat.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.METER_VALUES,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesRequest>(
-            'assets/json-schemas/ocpp/1.6/MeterValues.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.START_TRANSACTION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionRequest>(
-            'assets/json-schemas/ocpp/1.6/StartTransaction.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationRequest>(
-            'assets/json-schemas/ocpp/1.6/StatusNotification.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.STOP_TRANSACTION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionRequest>(
-            'assets/json-schemas/ocpp/1.6/StopTransaction.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
+    this.payloadValidatorFunctions = OCPP16ServiceUtils.createPayloadValidatorMap(
+      OCPP16ServiceUtils.createRequestPayloadConfigs(),
+      OCPP16ServiceUtils.createRequestFactoryOptions(moduleName, 'constructor'),
+      this.ajv
+    )
     this.buildRequestPayload = this.buildRequestPayload.bind(this)
   }
 
index 3b7a22111fb6ab172125db6ec340125ac766769a..06b7be4a44f11606fd3b884b3b6162955ec9e65b 100644 (file)
@@ -13,45 +13,28 @@ import {
 } from '../../../charging-station/index.js'
 import { OCPPError } from '../../../exception/index.js'
 import {
-  type ChangeConfigurationResponse,
   ChargingStationEvents,
   ErrorType,
-  type GenericResponse,
-  type GetConfigurationResponse,
-  type GetDiagnosticsResponse,
   type JsonType,
   OCPP16AuthorizationStatus,
   type OCPP16AuthorizeRequest,
   type OCPP16AuthorizeResponse,
   type OCPP16BootNotificationResponse,
-  type OCPP16ChangeAvailabilityResponse,
   OCPP16ChargePointStatus,
-  type OCPP16ClearChargingProfileResponse,
-  type OCPP16DataTransferResponse,
-  type OCPP16DiagnosticsStatusNotificationResponse,
-  type OCPP16FirmwareStatusNotificationResponse,
-  type OCPP16GetCompositeScheduleResponse,
-  type OCPP16HeartbeatResponse,
   OCPP16IncomingRequestCommand,
   type OCPP16MeterValue,
   type OCPP16MeterValuesRequest,
   type OCPP16MeterValuesResponse,
   OCPP16RequestCommand,
-  type OCPP16ReserveNowResponse,
   OCPP16StandardParametersKey,
   type OCPP16StartTransactionRequest,
   type OCPP16StartTransactionResponse,
-  type OCPP16StatusNotificationResponse,
   type OCPP16StopTransactionRequest,
   type OCPP16StopTransactionResponse,
-  type OCPP16TriggerMessageResponse,
-  type OCPP16UpdateFirmwareResponse,
   OCPPVersion,
   RegistrationStatusEnumType,
   ReservationTerminationReason,
   type ResponseHandler,
-  type SetChargingProfileResponse,
-  type UnlockConnectorResponse,
 } from '../../../types/index.js'
 import { Constants, convertToInt, isAsyncFunction, logger } from '../../../utils/index.js'
 import { OCPPResponseService } from '../OCPPResponseService.js'
@@ -65,7 +48,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
     ValidateFunction<JsonType>
   >
 
-  protected payloadValidateFunctions: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
+  protected payloadValidatorFunctions: Map<OCPP16RequestCommand, ValidateFunction<JsonType>>
   private readonly responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>
 
   public constructor () {
@@ -100,283 +83,17 @@ export class OCPP16ResponseService extends OCPPResponseService {
         this.handleResponseStopTransaction.bind(this) as ResponseHandler,
       ],
     ])
-    this.payloadValidateFunctions = new Map<OCPP16RequestCommand, ValidateFunction<JsonType>>([
-      [
-        OCPP16RequestCommand.AUTHORIZE,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeResponse>(
-            'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.BOOT_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationResponse>(
-            'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.DATA_TRANSFER,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
-            'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationResponse>(
-            'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationResponse>(
-            'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.HEARTBEAT,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatResponse>(
-            'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.METER_VALUES,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesResponse>(
-            'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.START_TRANSACTION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionResponse>(
-            'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationResponse>(
-            'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16RequestCommand.STOP_TRANSACTION,
-        this.ajv.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionResponse>(
-            'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
-    this.incomingRequestResponsePayloadValidateFunctions = new Map<
-      OCPP16IncomingRequestCommand,
-      ValidateFunction<JsonType>
-    >([
-      [
-        OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-            'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ChangeAvailabilityResponse>(
-            'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationResponse>(
-            'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CLEAR_CACHE,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-            'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearChargingProfileResponse>(
-            'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.DATA_TRANSFER,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
-            'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleResponse>(
-            'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.GET_CONFIGURATION,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationResponse>(
-            'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsResponse>(
-            'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-            'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-            'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.RESERVE_NOW,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowResponse>(
-            'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.RESET,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
-            'assets/json-schemas/ocpp/1.6/ResetResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileResponse>(
-            'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageResponse>(
-            'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorResponse>(
-            'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
-        this.ajvIncomingRequest.compile(
-          OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareResponse>(
-            'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
+    this.payloadValidatorFunctions = OCPP16ServiceUtils.createPayloadValidatorMap(
+      OCPP16ServiceUtils.createResponsePayloadConfigs(),
+      OCPP16ServiceUtils.createResponseFactoryOptions(moduleName, 'constructor'),
+      this.ajv
+    )
+    this.incomingRequestResponsePayloadValidateFunctions =
+      OCPP16ServiceUtils.createPayloadValidatorMap(
+        OCPP16ServiceUtils.createIncomingRequestResponsePayloadConfigs(),
+        OCPP16ServiceUtils.createIncomingRequestResponseFactoryOptions(moduleName, 'constructor'),
+        this.ajvIncomingRequest
+      )
     this.validatePayload = this.validatePayload.bind(this)
   }
 
@@ -862,7 +579,7 @@ export class OCPP16ResponseService extends OCPPResponseService {
     commandName: OCPP16RequestCommand,
     payload: JsonType
   ): boolean {
-    if (this.payloadValidateFunctions.has(commandName)) {
+    if (this.payloadValidatorFunctions.has(commandName)) {
       logger.debug(
         `${chargingStation.logPrefix()} ${moduleName}.validatePayload: Validating '${commandName}' response payload`
       )
index 24876bbdf8806d05d98758feb5dcb27444175747..0d3c99370ef2f9847a933e1998df3d98f471bff6 100644 (file)
@@ -28,11 +28,11 @@ import {
   type OCPP16ChargingProfile,
   type OCPP16ChargingSchedule,
   type OCPP16ClearChargingProfileRequest,
-  type OCPP16IncomingRequestCommand,
+  OCPP16IncomingRequestCommand,
   type OCPP16MeterValue,
   OCPP16MeterValueContext,
   OCPP16MeterValueUnit,
-  type OCPP16RequestCommand,
+  OCPP16RequestCommand,
   OCPP16StandardParametersKey,
   OCPP16StopTransactionReason,
   type OCPP16SupportedFeatureProfiles,
@@ -64,8 +64,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
     meterValue.sampledValue.push(
       OCPP16ServiceUtils.buildSampledValue(
         chargingStation.stationInfo?.ocppVersion,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        sampledValueTemplate!,
+        sampledValueTemplate,
         roundTo((meterStart ?? 0) / unitDivider, 4),
         OCPP16MeterValueContext.TRANSACTION_BEGIN
       )
@@ -379,6 +378,312 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
     }
   }
 
+  /**
+   * Factory options for OCPP 1.6 Incoming Request Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 1.6 incoming request validators
+   */
+  public static createIncomingRequestFactoryOptions = (moduleName: string, methodName: string) =>
+    OCPP16ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_16,
+      'assets/json-schemas/ocpp/1.6',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 1.6 Incoming Request Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createIncomingRequestPayloadConfigs = (): [
+    OCPP16IncomingRequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('CancelReservation.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ChangeAvailability.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ChangeConfiguration.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CLEAR_CACHE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ClearCache.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ClearChargingProfile.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.DATA_TRANSFER,
+      OCPP16ServiceUtils.PayloadValidatorConfig('DataTransfer.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('GetCompositeSchedule.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('GetConfiguration.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+      OCPP16ServiceUtils.PayloadValidatorConfig('GetDiagnostics.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('RemoteStartTransaction.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('RemoteStopTransaction.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.RESERVE_NOW,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ReserveNow.json'),
+    ],
+    [OCPP16IncomingRequestCommand.RESET, OCPP16ServiceUtils.PayloadValidatorConfig('Reset.json')],
+    [
+      OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('SetChargingProfile.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('TriggerMessage.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
+      OCPP16ServiceUtils.PayloadValidatorConfig('UnlockConnector.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('UpdateFirmware.json'),
+    ],
+  ]
+
+  /**
+   * Factory options for OCPP 1.6 Incoming Request Response Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 1.6 incoming request response validators
+   */
+  public static createIncomingRequestResponseFactoryOptions = (
+    moduleName: string,
+    methodName: string
+  ) =>
+    OCPP16ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_16,
+      'assets/json-schemas/ocpp/1.6',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 1.6 Incoming Request Response Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createIncomingRequestResponsePayloadConfigs = (): [
+    OCPP16IncomingRequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP16IncomingRequestCommand.CANCEL_RESERVATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('CancelReservationResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ChangeAvailabilityResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ChangeConfigurationResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CLEAR_CACHE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ClearCacheResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ClearChargingProfileResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.DATA_TRANSFER,
+      OCPP16ServiceUtils.PayloadValidatorConfig('DataTransferResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('GetCompositeScheduleResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('GetConfigurationResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+      OCPP16ServiceUtils.PayloadValidatorConfig('GetDiagnosticsResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('RemoteStartTransactionResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('RemoteStopTransactionResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.RESERVE_NOW,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ReserveNowResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.RESET,
+      OCPP16ServiceUtils.PayloadValidatorConfig('ResetResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('SetChargingProfileResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('TriggerMessageResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
+      OCPP16ServiceUtils.PayloadValidatorConfig('UnlockConnectorResponse.json'),
+    ],
+    [
+      OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('UpdateFirmwareResponse.json'),
+    ],
+  ]
+
+  /**
+   * Factory options for OCPP 1.6 Request Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 1.6 validators
+   */
+  public static createRequestFactoryOptions = (moduleName: string, methodName: string) =>
+    OCPP16ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_16,
+      'assets/json-schemas/ocpp/1.6',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 1.6 Request Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createRequestPayloadConfigs = (): [
+    OCPP16RequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [OCPP16RequestCommand.AUTHORIZE, OCPP16ServiceUtils.PayloadValidatorConfig('Authorize.json')],
+    [
+      OCPP16RequestCommand.BOOT_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('BootNotification.json'),
+    ],
+    [
+      OCPP16RequestCommand.DATA_TRANSFER,
+      OCPP16ServiceUtils.PayloadValidatorConfig('DataTransfer.json'),
+    ],
+    [
+      OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('DiagnosticsStatusNotification.json'),
+    ],
+    [
+      OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('FirmwareStatusNotification.json'),
+    ],
+    [OCPP16RequestCommand.HEARTBEAT, OCPP16ServiceUtils.PayloadValidatorConfig('Heartbeat.json')],
+    [
+      OCPP16RequestCommand.METER_VALUES,
+      OCPP16ServiceUtils.PayloadValidatorConfig('MeterValues.json'),
+    ],
+    [
+      OCPP16RequestCommand.START_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('StartTransaction.json'),
+    ],
+    [
+      OCPP16RequestCommand.STATUS_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('StatusNotification.json'),
+    ],
+    [
+      OCPP16RequestCommand.STOP_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('StopTransaction.json'),
+    ],
+  ]
+
+  /**
+   * Factory options for OCPP 1.6 Response Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 1.6 response validators
+   */
+  public static createResponseFactoryOptions = (moduleName: string, methodName: string) =>
+    OCPP16ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_16,
+      'assets/json-schemas/ocpp/1.6',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 1.6 Response Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createResponsePayloadConfigs = (): [
+    OCPP16RequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP16RequestCommand.AUTHORIZE,
+      OCPP16ServiceUtils.PayloadValidatorConfig('AuthorizeResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.BOOT_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('BootNotificationResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.DATA_TRANSFER,
+      OCPP16ServiceUtils.PayloadValidatorConfig('DataTransferResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('DiagnosticsStatusNotificationResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('FirmwareStatusNotificationResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.HEARTBEAT,
+      OCPP16ServiceUtils.PayloadValidatorConfig('HeartbeatResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.METER_VALUES,
+      OCPP16ServiceUtils.PayloadValidatorConfig('MeterValuesResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.START_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('StartTransactionResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.STATUS_NOTIFICATION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('StatusNotificationResponse.json'),
+    ],
+    [
+      OCPP16RequestCommand.STOP_TRANSACTION,
+      OCPP16ServiceUtils.PayloadValidatorConfig('StopTransactionResponse.json'),
+    ],
+  ]
+
   public static hasReservation = (
     chargingStation: ChargingStation,
     connectorId: number,
@@ -418,7 +723,7 @@ export class OCPP16ServiceUtils extends OCPPServiceUtils {
     moduleName?: string,
     methodName?: string
   ): JSONSchemaType<T> {
-    return OCPPServiceUtils.parseJsonSchemaFile<T>(
+    return OCPP16ServiceUtils.parseJsonSchemaFile<T>(
       relativePath,
       OCPPVersion.VERSION_16,
       moduleName,
index bde666dc9b8227c797d0e99391c2c104dd74b3e2..f6f68bfcb771fc43d28a683b3393afc23e327f13 100644 (file)
@@ -20,7 +20,6 @@ import {
   GetVariableStatusEnumType,
   type IncomingRequestHandler,
   type JsonType,
-  type OCPP20ClearCacheRequest,
   OCPP20ComponentName,
   OCPP20ConnectorStatusEnumType,
   OCPP20DeviceInfoVariableName,
@@ -70,7 +69,7 @@ import { getVariableMetadata, VARIABLE_REGISTRY } from './OCPP20VariableRegistry
 const moduleName = 'OCPP20IncomingRequestService'
 
 export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
-  protected payloadValidateFunctions: Map<OCPP20IncomingRequestCommand, ValidateFunction<JsonType>>
+  protected payloadValidatorFunctions: Map<OCPP20IncomingRequestCommand, ValidateFunction<JsonType>>
 
   private readonly incomingRequestHandlers: Map<
     OCPP20IncomingRequestCommand,
@@ -115,71 +114,11 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
         this.handleRequestSetVariables.bind(this) as unknown as IncomingRequestHandler,
       ],
     ])
-    this.payloadValidateFunctions = new Map<
-      OCPP20IncomingRequestCommand,
-      ValidateFunction<JsonType>
-    >([
-      [
-        OCPP20IncomingRequestCommand.CLEAR_CACHE,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheRequest>(
-            'assets/json-schemas/ocpp/2.0/ClearCacheRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.GET_BASE_REPORT,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20GetBaseReportRequest>(
-            'assets/json-schemas/ocpp/2.0/GetBaseReportRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.GET_VARIABLES,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20GetVariablesRequest>(
-            'assets/json-schemas/ocpp/2.0/GetVariablesRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20RequestStopTransactionRequest>(
-            'assets/json-schemas/ocpp/2.0/RequestStopTransactionRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.RESET,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ResetRequest>(
-            'assets/json-schemas/ocpp/2.0/ResetRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.SET_VARIABLES,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20SetVariablesRequest>(
-            'assets/json-schemas/ocpp/2.0/SetVariablesRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
+    this.payloadValidatorFunctions = OCPP20ServiceUtils.createPayloadValidatorMap(
+      OCPP20ServiceUtils.createIncomingRequestPayloadConfigs(),
+      OCPP20ServiceUtils.createIncomingRequestFactoryOptions(moduleName, 'constructor'),
+      this.ajv
+    )
     // Handle incoming request events
     this.on(
       OCPP20IncomingRequestCommand.GET_BASE_REPORT,
@@ -1555,7 +1494,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService {
     commandName: OCPP20IncomingRequestCommand,
     commandPayload: JsonType
   ): boolean {
-    if (this.payloadValidateFunctions.has(commandName)) {
+    if (this.payloadValidatorFunctions.has(commandName)) {
       return this.validateIncomingRequestPayload(chargingStation, commandName, commandPayload)
     }
     logger.warn(
index 7d323cd7f254fb122b8c7f25f9a3f3e1a5f753c8..b598efb230b5b32d52d5a8ae43b9736bb182e218 100644 (file)
@@ -10,11 +10,7 @@ import {
   ErrorType,
   type JsonObject,
   type JsonType,
-  type OCPP20BootNotificationRequest,
-  type OCPP20HeartbeatRequest,
-  type OCPP20NotifyReportRequest,
   OCPP20RequestCommand,
-  type OCPP20StatusNotificationRequest,
   OCPPVersion,
   type RequestParams,
 } from '../../../types/index.js'
@@ -26,55 +22,18 @@ import { OCPP20ServiceUtils } from './OCPP20ServiceUtils.js'
 const moduleName = 'OCPP20RequestService'
 
 export class OCPP20RequestService extends OCPPRequestService {
-  protected payloadValidateFunctions: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
+  protected payloadValidatorFunctions: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
 
   public constructor (ocppResponseService: OCPPResponseService) {
     // if (new.target.name === moduleName) {
     //   throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
     // }
     super(OCPPVersion.VERSION_201, ocppResponseService)
-    this.payloadValidateFunctions = new Map<OCPP20RequestCommand, ValidateFunction<JsonType>>([
-      [
-        OCPP20RequestCommand.BOOT_NOTIFICATION,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationRequest>(
-            'assets/json-schemas/ocpp/2.0/BootNotificationRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20RequestCommand.HEARTBEAT,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatRequest>(
-            'assets/json-schemas/ocpp/2.0/HeartbeatRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20RequestCommand.NOTIFY_REPORT,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20NotifyReportRequest>(
-            'assets/json-schemas/ocpp/2.0/NotifyReportRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20RequestCommand.STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationRequest>(
-            'assets/json-schemas/ocpp/2.0/StatusNotificationRequest.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
+    this.payloadValidatorFunctions = OCPP20ServiceUtils.createPayloadValidatorMap(
+      OCPP20ServiceUtils.createRequestPayloadConfigs(),
+      OCPP20ServiceUtils.createRequestFactoryOptions(moduleName, 'constructor'),
+      this.ajv
+    )
     this.buildRequestPayload = this.buildRequestPayload.bind(this)
   }
 
index a0c7c6590255c8820f9a93332140ca78c8aeeae9..e529c4a16ac39f28c2bb37109737d2f8a0166398 100644 (file)
@@ -9,15 +9,11 @@ import {
   ErrorType,
   type JsonType,
   type OCPP20BootNotificationResponse,
-  type OCPP20ClearCacheResponse,
-  type OCPP20GetBaseReportResponse,
   type OCPP20HeartbeatResponse,
   OCPP20IncomingRequestCommand,
   type OCPP20NotifyReportResponse,
   OCPP20OptionalVariableName,
   OCPP20RequestCommand,
-  type OCPP20RequestStartTransactionResponse,
-  type OCPP20RequestStopTransactionResponse,
   type OCPP20StatusNotificationResponse,
   OCPPVersion,
   RegistrationStatusEnumType,
@@ -35,7 +31,7 @@ export class OCPP20ResponseService extends OCPPResponseService {
     ValidateFunction<JsonType>
   >
 
-  protected payloadValidateFunctions: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
+  protected payloadValidatorFunctions: Map<OCPP20RequestCommand, ValidateFunction<JsonType>>
   private readonly responseHandlers: Map<OCPP20RequestCommand, ResponseHandler>
 
   public constructor () {
@@ -58,93 +54,17 @@ export class OCPP20ResponseService extends OCPPResponseService {
         this.handleResponseStatusNotification.bind(this) as ResponseHandler,
       ],
     ])
-    this.payloadValidateFunctions = new Map<OCPP20RequestCommand, ValidateFunction<JsonType>>([
-      [
-        OCPP20RequestCommand.BOOT_NOTIFICATION,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20BootNotificationResponse>(
-            'assets/json-schemas/ocpp/2.0/BootNotificationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20RequestCommand.HEARTBEAT,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20HeartbeatResponse>(
-            'assets/json-schemas/ocpp/2.0/HeartbeatResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20RequestCommand.NOTIFY_REPORT,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20NotifyReportResponse>(
-            'assets/json-schemas/ocpp/2.0/NotifyReportResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20RequestCommand.STATUS_NOTIFICATION,
-        this.ajv.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20StatusNotificationResponse>(
-            'assets/json-schemas/ocpp/2.0/StatusNotificationResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
-    this.incomingRequestResponsePayloadValidateFunctions = new Map<
-      OCPP20IncomingRequestCommand,
-      ValidateFunction<JsonType>
-    >([
-      [
-        OCPP20IncomingRequestCommand.CLEAR_CACHE,
-        this.ajvIncomingRequest.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20ClearCacheResponse>(
-            'assets/json-schemas/ocpp/2.0/ClearCacheResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.GET_BASE_REPORT,
-        this.ajvIncomingRequest.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20GetBaseReportResponse>(
-            'assets/json-schemas/ocpp/2.0/GetBaseReportResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION,
-        this.ajvIncomingRequest.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20RequestStartTransactionResponse>(
-            'assets/json-schemas/ocpp/2.0/RequestStartTransactionResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-      [
-        OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION,
-        this.ajvIncomingRequest.compile(
-          OCPP20ServiceUtils.parseJsonSchemaFile<OCPP20RequestStopTransactionResponse>(
-            'assets/json-schemas/ocpp/2.0/RequestStopTransactionResponse.json',
-            moduleName,
-            'constructor'
-          )
-        ),
-      ],
-    ])
+    this.payloadValidatorFunctions = OCPP20ServiceUtils.createPayloadValidatorMap(
+      OCPP20ServiceUtils.createResponsePayloadConfigs(),
+      OCPP20ServiceUtils.createResponseFactoryOptions(moduleName, 'constructor'),
+      this.ajv
+    )
+    this.incomingRequestResponsePayloadValidateFunctions =
+      OCPP20ServiceUtils.createPayloadValidatorMap(
+        OCPP20ServiceUtils.createIncomingRequestResponsePayloadConfigs(),
+        OCPP20ServiceUtils.createIncomingRequestResponseFactoryOptions(moduleName, 'constructor'),
+        this.ajvIncomingRequest
+      )
     this.validatePayload = this.validatePayload.bind(this)
   }
 
@@ -303,7 +223,7 @@ export class OCPP20ResponseService extends OCPPResponseService {
     commandName: OCPP20RequestCommand,
     payload: JsonType
   ): boolean {
-    if (this.payloadValidateFunctions.has(commandName)) {
+    if (this.payloadValidatorFunctions.has(commandName)) {
       logger.debug(
         `${chargingStation.logPrefix()} ${moduleName}.validatePayload: Validating '${commandName}' response payload`
       )
index b46b45dcfb49dce5609f45a9871415b13ba55d2f..2ea07cdf707e622bb0680a30eab3035af5f7f692 100644 (file)
@@ -8,6 +8,7 @@ import {
   ConnectorStatusEnum,
   type GenericResponse,
   type JsonType,
+  OCPP20IncomingRequestCommand,
   OCPP20RequestCommand,
   OCPP20TransactionEventEnumType,
   type OCPP20TransactionEventRequest,
@@ -20,6 +21,181 @@ import { OCPPServiceUtils, sendAndSetConnectorStatus } from '../OCPPServiceUtils
 import { OCPP20Constants } from './OCPP20Constants.js'
 
 export class OCPP20ServiceUtils extends OCPPServiceUtils {
+  /**
+   * Factory options for OCPP 2.0 Incoming Request Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 2.0 incoming request validators
+   */
+  public static createIncomingRequestFactoryOptions = (moduleName: string, methodName: string) =>
+    OCPP20ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_201,
+      'assets/json-schemas/ocpp/2.0',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 2.0 Incoming Request Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createIncomingRequestPayloadConfigs = (): [
+    OCPP20IncomingRequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP20IncomingRequestCommand.CLEAR_CACHE,
+      OCPP20ServiceUtils.PayloadValidatorConfig('ClearCacheRequest.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.GET_BASE_REPORT,
+      OCPP20ServiceUtils.PayloadValidatorConfig('GetBaseReportRequest.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.GET_VARIABLES,
+      OCPP20ServiceUtils.PayloadValidatorConfig('GetVariablesRequest.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('RequestStartTransactionRequest.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('RequestStopTransactionRequest.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.RESET,
+      OCPP20ServiceUtils.PayloadValidatorConfig('ResetRequest.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.SET_VARIABLES,
+      OCPP20ServiceUtils.PayloadValidatorConfig('SetVariablesRequest.json'),
+    ],
+  ]
+
+  /**
+   * Factory options for OCPP 2.0 Incoming Request Response Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 2.0 incoming request response validators
+   */
+  public static createIncomingRequestResponseFactoryOptions = (
+    moduleName: string,
+    methodName: string
+  ) =>
+    OCPP20ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_201,
+      'assets/json-schemas/ocpp/2.0',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * Configuration for OCPP 2.0 Incoming Request Response validators
+   * @returns Array of validator configuration tuples
+   */
+  public static createIncomingRequestResponsePayloadConfigs = (): [
+    OCPP20IncomingRequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP20IncomingRequestCommand.CLEAR_CACHE,
+      OCPP20ServiceUtils.PayloadValidatorConfig('ClearCacheResponse.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.GET_BASE_REPORT,
+      OCPP20ServiceUtils.PayloadValidatorConfig('GetBaseReportResponse.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.REQUEST_START_TRANSACTION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('RequestStartTransactionResponse.json'),
+    ],
+    [
+      OCPP20IncomingRequestCommand.REQUEST_STOP_TRANSACTION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('RequestStopTransactionResponse.json'),
+    ],
+  ]
+
+  /**
+   * Factory options for OCPP 2.0 Request Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 2.0 validators
+   */
+  public static createRequestFactoryOptions = (moduleName: string, methodName: string) =>
+    OCPP20ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_201,
+      'assets/json-schemas/ocpp/2.0',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 2.0 Request Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createRequestPayloadConfigs = (): [
+    OCPP20RequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP20RequestCommand.BOOT_NOTIFICATION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('BootNotificationRequest.json'),
+    ],
+    [
+      OCPP20RequestCommand.HEARTBEAT,
+      OCPP20ServiceUtils.PayloadValidatorConfig('HeartbeatRequest.json'),
+    ],
+    [
+      OCPP20RequestCommand.NOTIFY_REPORT,
+      OCPP20ServiceUtils.PayloadValidatorConfig('NotifyReportRequest.json'),
+    ],
+    [
+      OCPP20RequestCommand.STATUS_NOTIFICATION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('StatusNotificationRequest.json'),
+    ],
+  ]
+
+  /**
+   * Factory options for OCPP 2.0 Response Service
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Factory options object for OCPP 2.0 response validators
+   */
+  public static createResponseFactoryOptions = (moduleName: string, methodName: string) =>
+    OCPP20ServiceUtils.PayloadValidatorOptions(
+      OCPPVersion.VERSION_201,
+      'assets/json-schemas/ocpp/2.0',
+      moduleName,
+      methodName
+    )
+
+  /**
+   * OCPP 2.0 Response Service validator configurations
+   * @returns Array of validator configuration tuples
+   */
+  public static createResponsePayloadConfigs = (): [
+    OCPP20RequestCommand,
+    { schemaPath: string }
+  ][] => [
+    [
+      OCPP20RequestCommand.BOOT_NOTIFICATION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('BootNotificationResponse.json'),
+    ],
+    [
+      OCPP20RequestCommand.HEARTBEAT,
+      OCPP20ServiceUtils.PayloadValidatorConfig('HeartbeatResponse.json'),
+    ],
+    [
+      OCPP20RequestCommand.NOTIFY_REPORT,
+      OCPP20ServiceUtils.PayloadValidatorConfig('NotifyReportResponse.json'),
+    ],
+    [
+      OCPP20RequestCommand.STATUS_NOTIFICATION,
+      OCPP20ServiceUtils.PayloadValidatorConfig('StatusNotificationResponse.json'),
+    ],
+  ]
+
   public static enforceMessageLimits<
     T extends { attributeType?: unknown; component: unknown; variable: unknown }
   >(
@@ -101,7 +277,7 @@ export class OCPP20ServiceUtils extends OCPPServiceUtils {
     moduleName?: string,
     methodName?: string
   ): JSONSchemaType<T> {
-    return OCPPServiceUtils.parseJsonSchemaFile<T>(
+    return OCPP20ServiceUtils.parseJsonSchemaFile<T>(
       relativePath,
       OCPPVersion.VERSION_201,
       moduleName,
index 776335842e58da671dbc8774af2c18a6b37923a7..b588002665b5f33f6a1ff0ef4be9472ddb6fd05c 100644 (file)
@@ -25,7 +25,7 @@ const moduleName = 'OCPPIncomingRequestService'
 export abstract class OCPPIncomingRequestService extends EventEmitter {
   private static instance: null | OCPPIncomingRequestService = null
   protected readonly ajv: Ajv
-  protected abstract payloadValidateFunctions: Map<
+  protected abstract payloadValidatorFunctions: Map<
     IncomingRequestCommand,
     ValidateFunction<JsonType>
   >
@@ -76,7 +76,7 @@ export abstract class OCPPIncomingRequestService extends EventEmitter {
     if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
       return true
     }
-    const validate = this.payloadValidateFunctions.get(commandName)
+    const validate = this.payloadValidatorFunctions.get(commandName)
     if (validate?.(payload) === true) {
       return true
     }
index d5b944f127fc49a0af6ff3f5f1a83e7abd0a39c6..0d6d56b541467c869d0c6f47ca3247c1a7347dcb 100644 (file)
@@ -51,7 +51,7 @@ const defaultRequestParams: RequestParams = {
 export abstract class OCPPRequestService {
   private static instance: null | OCPPRequestService = null
   protected readonly ajv: Ajv
-  protected abstract payloadValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
+  protected abstract payloadValidatorFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
   private readonly ocppResponseService: OCPPResponseService
   private readonly version: OCPPVersion
 
@@ -488,13 +488,13 @@ export abstract class OCPPRequestService {
     if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
       return true
     }
-    if (!this.payloadValidateFunctions.has(commandName as RequestCommand)) {
+    if (!this.payloadValidatorFunctions.has(commandName as RequestCommand)) {
       logger.warn(
         `${chargingStation.logPrefix()} ${moduleName}.validateRequestPayload: No JSON schema found for command '${commandName}' PDU validation`
       )
       return true
     }
-    const validate = this.payloadValidateFunctions.get(commandName as RequestCommand)
+    const validate = this.payloadValidatorFunctions.get(commandName as RequestCommand)
     payload = clone<T>(payload)
     convertDateToISOString<T>(payload)
     if (validate?.(payload) === true) {
index 420358497d8670550a93c59ee78d648719da2d9e..d94bb33e60134a6a693193e3b12eda5a7791f00e 100644 (file)
@@ -30,7 +30,7 @@ export abstract class OCPPResponseService {
   protected readonly ajv: Ajv
   protected readonly ajvIncomingRequest: Ajv
   protected emptyResponseHandler = Constants.EMPTY_FUNCTION
-  protected abstract payloadValidateFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
+  protected abstract payloadValidatorFunctions: Map<RequestCommand, ValidateFunction<JsonType>>
   private readonly version: OCPPVersion
 
   protected constructor (version: OCPPVersion) {
@@ -71,7 +71,7 @@ export abstract class OCPPResponseService {
     if (chargingStation.stationInfo?.ocppStrictCompliance === false) {
       return true
     }
-    const validate = this.payloadValidateFunctions.get(commandName)
+    const validate = this.payloadValidatorFunctions.get(commandName)
     if (validate?.(payload) === true) {
       return true
     }
index c82e9a7ea278f48af94e5b81547df2504afa50fc..ec16a6b5824a596066de6fa155d469dde49322af 100644 (file)
@@ -1,5 +1,4 @@
-import type { ErrorObject, JSONSchemaType } from 'ajv'
-
+import _Ajv, { type ErrorObject, type JSONSchemaType, type ValidateFunction } from 'ajv'
 import { isDate } from 'date-fns'
 import { randomInt } from 'node:crypto'
 import { readFileSync } from 'node:fs'
@@ -71,6 +70,10 @@ import { OCPP16Constants } from './1.6/OCPP16Constants.js'
 import { OCPP20Constants } from './2.0/OCPP20Constants.js'
 import { OCPPConstants } from './OCPPConstants.js'
 
+type Ajv = _Ajv.default
+// eslint-disable-next-line @typescript-eslint/no-redeclare
+const Ajv = _Ajv.default
+
 interface MultiPhaseMeasurandData {
   perPhaseTemplates: MeasurandPerPhaseSampledValueTemplates
   template: SampledValueTemplate
@@ -403,8 +406,7 @@ const buildVoltageMeasurandValue = (
 
   const voltageSampledValueTemplateValue = isNotEmptyString(voltageSampledValueTemplate.value)
     ? Number.parseInt(voltageSampledValueTemplate.value)
-    : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-    chargingStation.stationInfo.voltageOut!
+    : chargingStation.getVoltageOut()
   const fluctuationPercent =
     voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
   const voltageMeasurandValue = getRandomFloatFluctuatedRounded(
@@ -426,7 +428,7 @@ const addMainVoltageToMeterValue = (
   if (
     chargingStation.getNumberOfPhases() !== 3 ||
     (chargingStation.getNumberOfPhases() === 3 &&
-      chargingStation.stationInfo.mainVoltageMeterValues === true)
+      chargingStation.stationInfo?.mainVoltageMeterValues === true)
   ) {
     meterValue.sampledValue.push(
       buildSampledValue(
@@ -458,8 +460,7 @@ const addPhaseVoltageToMeterValue = (
       voltagePhaseLineToNeutralSampledValueTemplate.value
     )
       ? Number.parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      chargingStation.stationInfo.voltageOut!
+      : chargingStation.getVoltageOut()
     const fluctuationPhaseToNeutralPercent =
       voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ??
       Constants.DEFAULT_FLUCTUATION_PERCENT
@@ -493,9 +494,7 @@ const addLineToLineVoltageToMeterValue = (
         : chargingStation.getNumberOfPhases().toString()
     }` as MeterValuePhase
     const voltagePhaseLineToLineValueRounded = roundTo(
-      Math.sqrt(chargingStation.getNumberOfPhases()) *
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        chargingStation.stationInfo.voltageOut!,
+      Math.sqrt(chargingStation.getNumberOfPhases()) * chargingStation.getVoltageOut(),
       2
     )
     const voltagePhaseLineToLineSampledValueTemplate = getSampledValueTemplate(
@@ -933,8 +932,7 @@ const buildCurrentMeasurandValue = (
       connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
         chargingStation.getNumberOfPhases(),
         connectorMaximumAvailablePower,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        chargingStation.stationInfo.voltageOut!
+        chargingStation.getVoltageOut()
       )
       if (chargingStation.getNumberOfPhases() === 3) {
         const defaultFluctuatedAmperagePerPhase = isNotEmptyString(currentTemplate.value)
@@ -1036,8 +1034,7 @@ const buildCurrentMeasurandValue = (
     case CurrentType.DC:
       connectorMaximumAmperage = DCElectricUtils.amperage(
         connectorMaximumAvailablePower,
-        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        chargingStation.stationInfo.voltageOut!
+        chargingStation.getVoltageOut()
       )
       currentValues.allPhases = isNotEmptyString(currentTemplate.value)
         ? getRandomFloatFluctuatedRounded(
@@ -1209,13 +1206,11 @@ export const buildMeterValue = (
             ? ACElectricUtils.amperagePerPhaseFromPower(
               chargingStation.getNumberOfPhases(),
               connectorMaximumAvailablePower,
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              chargingStation.stationInfo.voltageOut!
+              chargingStation.getVoltageOut()
             )
             : DCElectricUtils.amperage(
               connectorMaximumAvailablePower,
-              // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-              chargingStation.stationInfo.voltageOut!
+              chargingStation.getVoltageOut()
             )
         const connectorMinimumAmperage = currentMeasurand.template.minimumValue ?? 0
 
@@ -1596,20 +1591,6 @@ const getSampledValueTemplate = (
   )
 }
 
-function buildSampledValue (
-  ocppVersion: OCPPVersion.VERSION_16 | undefined,
-  sampledValueTemplate: SampledValueTemplate,
-  value: number,
-  context?: MeterValueContext,
-  phase?: MeterValuePhase
-): OCPP16SampledValue
-function buildSampledValue (
-  ocppVersion: OCPPVersion.VERSION_20 | OCPPVersion.VERSION_201 | undefined,
-  sampledValueTemplate: SampledValueTemplate,
-  value: number,
-  context?: MeterValueContext,
-  phase?: MeterValuePhase
-): OCPP20SampledValue
 /**
  * Builds a sampled value object according to the specified OCPP version
  * @param ocppVersion - The OCPP version to use for formatting the sampled value
@@ -1799,6 +1780,42 @@ export class OCPPServiceUtils {
     // This is intentional
   }
 
+  /**
+   * Creates a Map of compiled OCPP payload validators from configurations
+   * Reduces code duplication across OCPP services
+   * @param configs - Array of tuples containing command and validator configuration
+   * @param options - Factory options including OCPP version, schema directory, etc.
+   * @param options.ocppVersion - The OCPP version for schema validation
+   * @param options.schemaDir - Directory path containing JSON schemas
+   * @param options.moduleName - Name of the module for logging
+   * @param options.methodName - Name of the method for logging
+   * @param ajvInstance - Configured Ajv instance for validation
+   * @returns Map of commands to their compiled validation functions
+   */
+  public static createPayloadValidatorMap<Command extends JsonType>(
+    configs: [Command, { schemaPath: string }][],
+    options: {
+      methodName: string
+      moduleName: string
+      ocppVersion: OCPPVersion
+      schemaDir: string
+    },
+    ajvInstance: Ajv
+  ): Map<Command, ValidateFunction<JsonType>> {
+    return new Map<Command, ValidateFunction<JsonType>>(
+      configs.map(([command, config]) => {
+        const fullSchemaPath = `${options.schemaDir}/${config.schemaPath}`
+        const schema = OCPPServiceUtils.parseJsonSchemaFile<JsonType>(
+          fullSchemaPath,
+          options.ocppVersion,
+          options.moduleName,
+          options.methodName
+        )
+        return [command, ajvInstance.compile(schema)]
+      })
+    )
+  }
+
   public static isConnectorIdValid (
     chargingStation: ChargingStation,
     ocppCommand: IncomingRequestCommand,
@@ -1873,6 +1890,37 @@ export class OCPPServiceUtils {
     return false
   }
 
+  /**
+   * Configuration for a single payload validator
+   * @param schemaPath - Path to the JSON schema file
+   * @returns Configuration object for payload validator creation
+   */
+  public static readonly PayloadValidatorConfig = (schemaPath: string) =>
+    ({
+      schemaPath,
+    }) as const
+
+  /**
+   * Options for payload validator creation
+   * @param ocppVersion - The OCPP version
+   * @param schemaDir - Directory containing JSON schemas
+   * @param moduleName - Name of the OCPP module
+   * @param methodName - Name of the method/command
+   * @returns Options object for payload validator creation
+   */
+  public static readonly PayloadValidatorOptions = (
+    ocppVersion: OCPPVersion,
+    schemaDir: string,
+    moduleName: string,
+    methodName: string
+  ) =>
+    ({
+      methodName,
+      moduleName,
+      ocppVersion,
+      schemaDir,
+    }) as const
+
   protected static parseJsonSchemaFile<T extends JsonType>(
     relativePath: string,
     ocppVersion: OCPPVersion,