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