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