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