1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
3 import type { JSONSchemaType
} from
'ajv';
5 import { OCPP16Constants
} from
'./OCPP16Constants';
6 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils';
7 import type { ChargingStation
} from
'../../../charging-station';
8 import { OCPPError
} from
'../../../exception';
13 type OCPP16AuthorizeRequest
,
14 type OCPP16BootNotificationRequest
,
15 type OCPP16DataTransferRequest
,
16 type OCPP16DiagnosticsStatusNotificationRequest
,
17 type OCPP16FirmwareStatusNotificationRequest
,
18 type OCPP16HeartbeatRequest
,
19 type OCPP16MeterValuesRequest
,
21 type OCPP16StartTransactionRequest
,
22 type OCPP16StatusNotificationRequest
,
23 type OCPP16StopTransactionRequest
,
26 } from
'../../../types';
27 import { Constants
, generateUUID
} from
'../../../utils';
28 import { OCPPRequestService
} from
'../OCPPRequestService';
29 import type { OCPPResponseService
} from
'../OCPPResponseService';
31 const moduleName
= 'OCPP16RequestService';
33 export class OCPP16RequestService
extends OCPPRequestService
{
34 protected jsonSchemas
: Map
<OCPP16RequestCommand
, JSONSchemaType
<JsonObject
>>;
36 public constructor(ocppResponseService
: OCPPResponseService
) {
37 // if (new.target?.name === moduleName) {
38 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
40 super(OCPPVersion
.VERSION_16
, ocppResponseService
);
41 this.jsonSchemas
= new Map
<OCPP16RequestCommand
, JSONSchemaType
<JsonObject
>>([
43 OCPP16RequestCommand
.AUTHORIZE
,
44 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16AuthorizeRequest
>(
45 'assets/json-schemas/ocpp/1.6/Authorize.json',
51 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
52 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16BootNotificationRequest
>(
53 'assets/json-schemas/ocpp/1.6/BootNotification.json',
59 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
60 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DiagnosticsStatusNotificationRequest
>(
61 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json',
67 OCPP16RequestCommand
.HEARTBEAT
,
68 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16HeartbeatRequest
>(
69 'assets/json-schemas/ocpp/1.6/Heartbeat.json',
75 OCPP16RequestCommand
.METER_VALUES
,
76 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16MeterValuesRequest
>(
77 'assets/json-schemas/ocpp/1.6/MeterValues.json',
83 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
84 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StatusNotificationRequest
>(
85 'assets/json-schemas/ocpp/1.6/StatusNotification.json',
91 OCPP16RequestCommand
.START_TRANSACTION
,
92 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StartTransactionRequest
>(
93 'assets/json-schemas/ocpp/1.6/StartTransaction.json',
99 OCPP16RequestCommand
.STOP_TRANSACTION
,
100 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StopTransactionRequest
>(
101 'assets/json-schemas/ocpp/1.6/StopTransaction.json',
107 OCPP16RequestCommand
.DATA_TRANSFER
,
108 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferRequest
>(
109 'assets/json-schemas/ocpp/1.6/DataTransfer.json',
115 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
116 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16FirmwareStatusNotificationRequest
>(
117 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json',
123 this.buildRequestPayload
= this.buildRequestPayload
.bind(this) as <Request
extends JsonType
>(
124 chargingStation
: ChargingStation
,
125 commandName
: OCPP16RequestCommand
,
126 commandParams
?: JsonType
,
130 public async requestHandler
<RequestType
extends JsonType
, ResponseType
extends JsonType
>(
131 chargingStation
: ChargingStation
,
132 commandName
: OCPP16RequestCommand
,
133 commandParams
?: JsonType
,
134 params
?: RequestParams
,
135 ): Promise
<ResponseType
> {
136 // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
137 if (OCPP16ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
) === true) {
138 return (await this.sendMessage(
141 this.buildRequestPayload
<RequestType
>(chargingStation
, commandName
, commandParams
),
146 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
148 ErrorType
.NOT_SUPPORTED
,
149 `Unsupported OCPP command '${commandName}'`,
155 private buildRequestPayload
<Request
extends JsonType
>(
156 chargingStation
: ChargingStation
,
157 commandName
: OCPP16RequestCommand
,
158 commandParams
?: JsonType
,
160 let connectorId
: number | undefined;
161 let energyActiveImportRegister
: number;
162 commandParams
= commandParams
as JsonObject
;
163 switch (commandName
) {
164 case OCPP16RequestCommand
.BOOT_NOTIFICATION
:
165 case OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
:
166 case OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
:
167 case OCPP16RequestCommand
.METER_VALUES
:
168 case OCPP16RequestCommand
.STATUS_NOTIFICATION
:
169 case OCPP16RequestCommand
.DATA_TRANSFER
:
170 return commandParams
as unknown
as Request
;
171 case OCPP16RequestCommand
.AUTHORIZE
:
173 idTag
: Constants
.DEFAULT_IDTAG
,
175 } as unknown
as Request
;
176 case OCPP16RequestCommand
.HEARTBEAT
:
177 return OCPP16Constants
.OCPP_REQUEST_EMPTY
as unknown
as Request
;
178 case OCPP16RequestCommand
.START_TRANSACTION
:
180 idTag
: Constants
.DEFAULT_IDTAG
,
181 meterStart
: chargingStation
.getEnergyActiveImportRegisterByConnectorId(
182 commandParams
?.connectorId
as number,
185 timestamp
: new Date(),
187 } as unknown
as Request
;
188 case OCPP16RequestCommand
.STOP_TRANSACTION
:
189 chargingStation
.getTransactionDataMeterValues() &&
190 (connectorId
= chargingStation
.getConnectorIdByTransactionId(
191 commandParams
?.transactionId
as number,
193 energyActiveImportRegister
= chargingStation
.getEnergyActiveImportRegisterByTransactionId(
194 commandParams
?.transactionId
as number,
198 idTag
: chargingStation
.getTransactionIdTag(commandParams
?.transactionId
as number),
199 meterStop
: energyActiveImportRegister
,
200 timestamp
: new Date(),
201 ...(chargingStation
.getTransactionDataMeterValues() && {
202 transactionData
: OCPP16ServiceUtils
.buildTransactionDataMeterValues(
203 chargingStation
.getConnectorStatus(connectorId
!)!.transactionBeginMeterValue
!,
204 OCPP16ServiceUtils
.buildTransactionEndMeterValue(
207 energyActiveImportRegister
,
212 } as unknown
as Request
;
214 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
216 ErrorType
.NOT_SUPPORTED
,
217 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
218 `Unsupported OCPP command '${commandName}'`,