1 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
3 import type { ValidateFunction
} from
'ajv'
5 import type { ChargingStation
} from
'../../../charging-station/index.js'
6 import { OCPPError
} from
'../../../exception/index.js'
11 type OCPP16AuthorizeRequest
,
12 type OCPP16BootNotificationRequest
,
13 OCPP16ChargePointStatus
,
14 type OCPP16DataTransferRequest
,
15 type OCPP16DiagnosticsStatusNotificationRequest
,
16 type OCPP16FirmwareStatusNotificationRequest
,
17 type OCPP16HeartbeatRequest
,
18 type OCPP16MeterValuesRequest
,
20 type OCPP16StartTransactionRequest
,
21 type OCPP16StatusNotificationRequest
,
22 type OCPP16StopTransactionRequest
,
25 } from
'../../../types/index.js'
26 import { Constants
, generateUUID
} from
'../../../utils/index.js'
27 import { OCPPRequestService
} from
'../OCPPRequestService.js'
28 import type { OCPPResponseService
} from
'../OCPPResponseService.js'
29 import { OCPP16Constants
} from
'./OCPP16Constants.js'
30 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils.js'
32 const moduleName
= 'OCPP16RequestService'
34 export class OCPP16RequestService
extends OCPPRequestService
{
35 protected payloadValidateFunctions
: Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>
37 public constructor (ocppResponseService
: OCPPResponseService
) {
38 // if (new.target.name === moduleName) {
39 // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
41 super(OCPPVersion
.VERSION_16
, ocppResponseService
)
42 this.payloadValidateFunctions
= new Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>([
44 OCPP16RequestCommand
.AUTHORIZE
,
47 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16AuthorizeRequest
>(
48 'assets/json-schemas/ocpp/1.6/Authorize.json',
56 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
59 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16BootNotificationRequest
>(
60 'assets/json-schemas/ocpp/1.6/BootNotification.json',
68 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
71 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DiagnosticsStatusNotificationRequest
>(
72 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json',
80 OCPP16RequestCommand
.HEARTBEAT
,
83 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16HeartbeatRequest
>(
84 'assets/json-schemas/ocpp/1.6/Heartbeat.json',
92 OCPP16RequestCommand
.METER_VALUES
,
95 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16MeterValuesRequest
>(
96 'assets/json-schemas/ocpp/1.6/MeterValues.json',
104 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
107 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StatusNotificationRequest
>(
108 'assets/json-schemas/ocpp/1.6/StatusNotification.json',
116 OCPP16RequestCommand
.START_TRANSACTION
,
119 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StartTransactionRequest
>(
120 'assets/json-schemas/ocpp/1.6/StartTransaction.json',
128 OCPP16RequestCommand
.STOP_TRANSACTION
,
131 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StopTransactionRequest
>(
132 'assets/json-schemas/ocpp/1.6/StopTransaction.json',
140 OCPP16RequestCommand
.DATA_TRANSFER
,
143 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferRequest
>(
144 'assets/json-schemas/ocpp/1.6/DataTransfer.json',
152 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
155 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16FirmwareStatusNotificationRequest
>(
156 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json',
164 this.buildRequestPayload
= this.buildRequestPayload
.bind(this)
167 public async requestHandler
<RequestType
extends JsonType
, ResponseType
extends JsonType
>(
168 chargingStation
: ChargingStation
,
169 commandName
: OCPP16RequestCommand
,
170 commandParams
?: RequestType
,
171 params
?: RequestParams
172 ): Promise
<ResponseType
> {
173 // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
174 if (OCPP16ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
)) {
175 // Pre request actions hook
176 switch (commandName
) {
177 case OCPP16RequestCommand
.START_TRANSACTION
:
178 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
180 (commandParams
as OCPP16StartTransactionRequest
).connectorId
,
181 OCPP16ChargePointStatus
.Preparing
185 return (await this.sendMessage(
188 this.buildRequestPayload
<RequestType
>(chargingStation
, commandName
, commandParams
),
193 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
195 ErrorType
.NOT_SUPPORTED
,
196 `Unsupported OCPP command ${commandName}`,
202 private buildRequestPayload
<Request
extends JsonType
>(
203 chargingStation
: ChargingStation
,
204 commandName
: OCPP16RequestCommand
,
205 commandParams
?: JsonType
207 let connectorId
: number | undefined
208 let energyActiveImportRegister
: number
209 commandParams
= commandParams
as JsonObject
210 switch (commandName
) {
211 case OCPP16RequestCommand
.BOOT_NOTIFICATION
:
212 case OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
:
213 case OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
:
214 case OCPP16RequestCommand
.METER_VALUES
:
215 case OCPP16RequestCommand
.STATUS_NOTIFICATION
:
216 case OCPP16RequestCommand
.DATA_TRANSFER
:
217 return commandParams
as unknown
as Request
218 case OCPP16RequestCommand
.AUTHORIZE
:
220 idTag
: Constants
.DEFAULT_IDTAG
,
222 } as unknown
as Request
223 case OCPP16RequestCommand
.HEARTBEAT
:
224 return OCPP16Constants
.OCPP_REQUEST_EMPTY
as unknown
as Request
225 case OCPP16RequestCommand
.START_TRANSACTION
:
227 idTag
: Constants
.DEFAULT_IDTAG
,
228 meterStart
: chargingStation
.getEnergyActiveImportRegisterByConnectorId(
229 commandParams
.connectorId
as number,
232 timestamp
: new Date(),
233 ...(OCPP16ServiceUtils
.hasReservation(
235 commandParams
.connectorId
as number,
236 commandParams
.idTag
as string
238 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
239 reservationId
: chargingStation
.getReservationBy(
241 chargingStation
.getConnectorStatus(0)?.status === OCPP16ChargePointStatus
.Reserved
243 : (commandParams
.connectorId
as number)
247 } as unknown
as Request
248 case OCPP16RequestCommand
.STOP_TRANSACTION
:
249 chargingStation
.stationInfo
?.transactionDataMeterValues
=== true &&
250 (connectorId
= chargingStation
.getConnectorIdByTransactionId(
251 commandParams
.transactionId
as number
253 energyActiveImportRegister
= chargingStation
.getEnergyActiveImportRegisterByTransactionId(
254 commandParams
.transactionId
as number,
258 idTag
: chargingStation
.getTransactionIdTag(commandParams
.transactionId
as number),
259 meterStop
: energyActiveImportRegister
,
260 timestamp
: new Date(),
261 ...(chargingStation
.stationInfo
?.transactionDataMeterValues
=== true && {
262 transactionData
: OCPP16ServiceUtils
.buildTransactionDataMeterValues(
263 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
264 chargingStation
.getConnectorStatus(connectorId
!)!.transactionBeginMeterValue
!,
265 OCPP16ServiceUtils
.buildTransactionEndMeterValue(
267 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
269 energyActiveImportRegister
274 } as unknown
as Request
276 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
278 ErrorType
.NOT_SUPPORTED
,
279 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
280 `Unsupported OCPP command ${commandName}`,