Merge branch 'main' into reservation-feature
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16RequestService.ts
1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
2
3 import type { JSONSchemaType } from 'ajv';
4
5 import { OCPP16Constants } from './OCPP16Constants';
6 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
7 import type { ChargingStation } from '../../../charging-station';
8 import { OCPPError } from '../../../exception';
9 import {
10 ErrorType,
11 type JsonObject,
12 type JsonType,
13 type OCPP16AuthorizeRequest,
14 type OCPP16BootNotificationRequest,
15 type OCPP16DataTransferRequest,
16 type OCPP16DiagnosticsStatusNotificationRequest,
17 type OCPP16FirmwareStatusNotificationRequest,
18 type OCPP16HeartbeatRequest,
19 type OCPP16MeterValuesRequest,
20 OCPP16RequestCommand,
21 type OCPP16StartTransactionRequest,
22 type OCPP16StatusNotificationRequest,
23 type OCPP16StopTransactionRequest,
24 OCPPVersion,
25 type RequestParams,
26 } from '../../../types';
27 import type {
28 OCPP16CancelReservationRequest,
29 OCPP16ReserveNowRequest,
30 } from '../../../types/ocpp/1.6/Requests';
31 import { Constants, Utils } from '../../../utils';
32 import { OCPPRequestService } from '../OCPPRequestService';
33 import type { OCPPResponseService } from '../OCPPResponseService';
34
35 const moduleName = 'OCPP16RequestService';
36
37 export class OCPP16RequestService extends OCPPRequestService {
38 protected jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>;
39
40 public constructor(ocppResponseService: OCPPResponseService) {
41 // if (new.target?.name === moduleName) {
42 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
43 // }
44 super(OCPPVersion.VERSION_16, ocppResponseService);
45 this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>([
46 [
47 OCPP16RequestCommand.AUTHORIZE,
48 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeRequest>(
49 'assets/json-schemas/ocpp/1.6/Authorize.json',
50 moduleName,
51 'constructor'
52 ),
53 ],
54 [
55 OCPP16RequestCommand.BOOT_NOTIFICATION,
56 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationRequest>(
57 'assets/json-schemas/ocpp/1.6/BootNotification.json',
58 moduleName,
59 'constructor'
60 ),
61 ],
62 [
63 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
64 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationRequest>(
65 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotification.json',
66 moduleName,
67 'constructor'
68 ),
69 ],
70 [
71 OCPP16RequestCommand.HEARTBEAT,
72 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatRequest>(
73 'assets/json-schemas/ocpp/1.6/Heartbeat.json',
74 moduleName,
75 'constructor'
76 ),
77 ],
78 [
79 OCPP16RequestCommand.METER_VALUES,
80 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesRequest>(
81 'assets/json-schemas/ocpp/1.6/MeterValues.json',
82 moduleName,
83 'constructor'
84 ),
85 ],
86 [
87 OCPP16RequestCommand.STATUS_NOTIFICATION,
88 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationRequest>(
89 'assets/json-schemas/ocpp/1.6/StatusNotification.json',
90 moduleName,
91 'constructor'
92 ),
93 ],
94 [
95 OCPP16RequestCommand.START_TRANSACTION,
96 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionRequest>(
97 'assets/json-schemas/ocpp/1.6/StartTransaction.json',
98 moduleName,
99 'constructor'
100 ),
101 ],
102 [
103 OCPP16RequestCommand.STOP_TRANSACTION,
104 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionRequest>(
105 'assets/json-schemas/ocpp/1.6/StopTransaction.json',
106 moduleName,
107 'constructor'
108 ),
109 ],
110 [
111 OCPP16RequestCommand.DATA_TRANSFER,
112 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
113 'assets/json-schemas/ocpp/1.6/DataTransfer.json',
114 moduleName,
115 'constructor'
116 ),
117 ],
118 [
119 OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
120 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationRequest>(
121 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotification.json',
122 moduleName,
123 'constructor'
124 ),
125 ],
126 [
127 OCPP16RequestCommand.RESERVE_NOW,
128 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ReserveNowRequest>(
129 'assets/json-schemas/ocpp/1.6/ReserveNow.json',
130 moduleName,
131 'constructor'
132 ),
133 ],
134 [
135 OCPP16RequestCommand.CANCEL_RESERVATION,
136 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16CancelReservationRequest>(
137 'assets/json-schemas/ocpp/1.6/CancelReservation.json',
138 moduleName,
139 'constructor'
140 ),
141 ],
142 ]);
143 this.buildRequestPayload = this.buildRequestPayload.bind(this) as <Request extends JsonType>(
144 chargingStation: ChargingStation,
145 commandName: OCPP16RequestCommand,
146 commandParams?: JsonType
147 ) => Request;
148 }
149
150 public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
151 chargingStation: ChargingStation,
152 commandName: OCPP16RequestCommand,
153 commandParams?: JsonType,
154 params?: RequestParams
155 ): Promise<ResponseType> {
156 // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
157 if (OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName) === true) {
158 return (await this.sendMessage(
159 chargingStation,
160 Utils.generateUUID(),
161 this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams),
162 commandName,
163 params
164 )) as ResponseType;
165 }
166 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
167 throw new OCPPError(
168 ErrorType.NOT_SUPPORTED,
169 `Unsupported OCPP command '${commandName}'`,
170 commandName,
171 commandParams
172 );
173 }
174
175 private buildRequestPayload<Request extends JsonType>(
176 chargingStation: ChargingStation,
177 commandName: OCPP16RequestCommand,
178 commandParams?: JsonType
179 ): Request {
180 let connectorId: number;
181 let energyActiveImportRegister: number;
182 commandParams = commandParams as JsonObject;
183 switch (commandName) {
184 case OCPP16RequestCommand.BOOT_NOTIFICATION:
185 case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
186 case OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION:
187 case OCPP16RequestCommand.METER_VALUES:
188 case OCPP16RequestCommand.STATUS_NOTIFICATION:
189 case OCPP16RequestCommand.DATA_TRANSFER:
190 return commandParams as unknown as Request;
191 case OCPP16RequestCommand.AUTHORIZE:
192 return {
193 idTag: Constants.DEFAULT_IDTAG,
194 ...commandParams,
195 } as unknown as Request;
196 case OCPP16RequestCommand.HEARTBEAT:
197 return OCPP16Constants.OCPP_REQUEST_EMPTY as unknown as Request;
198 case OCPP16RequestCommand.START_TRANSACTION:
199 return {
200 idTag: Constants.DEFAULT_IDTAG,
201 meterStart: chargingStation.getEnergyActiveImportRegisterByConnectorId(
202 commandParams?.connectorId as number,
203 true
204 ),
205 timestamp: new Date(),
206 ...commandParams,
207 } as unknown as Request;
208 case OCPP16RequestCommand.STOP_TRANSACTION:
209 chargingStation.getTransactionDataMeterValues() &&
210 (connectorId = chargingStation.getConnectorIdByTransactionId(
211 commandParams?.transactionId as number
212 ));
213 energyActiveImportRegister = chargingStation.getEnergyActiveImportRegisterByTransactionId(
214 commandParams?.transactionId as number,
215 true
216 );
217 return {
218 idTag: chargingStation.getTransactionIdTag(commandParams?.transactionId as number),
219 meterStop: energyActiveImportRegister,
220 timestamp: new Date(),
221 ...(chargingStation.getTransactionDataMeterValues() && {
222 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
223 chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue,
224 OCPP16ServiceUtils.buildTransactionEndMeterValue(
225 chargingStation,
226 connectorId,
227 energyActiveImportRegister
228 )
229 ),
230 }),
231 ...commandParams,
232 } as unknown as Request;
233 default:
234 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
235 throw new OCPPError(
236 ErrorType.NOT_SUPPORTED,
237 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
238 `Unsupported OCPP command '${commandName}'`,
239 commandName,
240 commandParams
241 );
242 }
243 }
244 }