refactor: remove getter on stationInfo properties
[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 OCPP16ChargePointStatus,
16 type OCPP16DataTransferRequest,
17 type OCPP16DiagnosticsStatusNotificationRequest,
18 type OCPP16FirmwareStatusNotificationRequest,
19 type OCPP16HeartbeatRequest,
20 type OCPP16MeterValuesRequest,
21 OCPP16RequestCommand,
22 type OCPP16StartTransactionRequest,
23 type OCPP16StatusNotificationRequest,
24 type OCPP16StopTransactionRequest,
25 OCPPVersion,
26 type RequestParams,
27 } from '../../../types';
28 import { Constants, generateUUID } from '../../../utils';
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<JsonType>>;
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<JsonType>>([
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 = this.buildRequestPayload.bind(this) as <Request extends JsonType>(
125 chargingStation: ChargingStation,
126 commandName: OCPP16RequestCommand,
127 commandParams?: JsonType,
128 ) => Request;
129 }
130
131 public async requestHandler<RequestType extends JsonType, ResponseType extends JsonType>(
132 chargingStation: ChargingStation,
133 commandName: OCPP16RequestCommand,
134 commandParams?: JsonType,
135 params?: RequestParams,
136 ): Promise<ResponseType> {
137 // FIXME?: add sanity checks on charging station availability, connector availability, connector status, etc.
138 if (OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName) === true) {
139 return (await this.sendMessage(
140 chargingStation,
141 generateUUID(),
142 this.buildRequestPayload<RequestType>(chargingStation, commandName, commandParams),
143 commandName,
144 params,
145 )) as ResponseType;
146 }
147 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
148 throw new OCPPError(
149 ErrorType.NOT_SUPPORTED,
150 `Unsupported OCPP command '${commandName}'`,
151 commandName,
152 commandParams,
153 );
154 }
155
156 private buildRequestPayload<Request extends JsonType>(
157 chargingStation: ChargingStation,
158 commandName: OCPP16RequestCommand,
159 commandParams?: JsonType,
160 ): Request {
161 let connectorId: number | undefined;
162 let energyActiveImportRegister: number;
163 commandParams = commandParams as JsonObject;
164 switch (commandName) {
165 case OCPP16RequestCommand.BOOT_NOTIFICATION:
166 case OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION:
167 case OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION:
168 case OCPP16RequestCommand.METER_VALUES:
169 case OCPP16RequestCommand.STATUS_NOTIFICATION:
170 case OCPP16RequestCommand.DATA_TRANSFER:
171 return commandParams as unknown as Request;
172 case OCPP16RequestCommand.AUTHORIZE:
173 return {
174 idTag: Constants.DEFAULT_IDTAG,
175 ...commandParams,
176 } as unknown as Request;
177 case OCPP16RequestCommand.HEARTBEAT:
178 return OCPP16Constants.OCPP_REQUEST_EMPTY as unknown as Request;
179 case OCPP16RequestCommand.START_TRANSACTION:
180 return {
181 idTag: Constants.DEFAULT_IDTAG,
182 meterStart: chargingStation.getEnergyActiveImportRegisterByConnectorId(
183 commandParams?.connectorId as number,
184 true,
185 ),
186 timestamp: new Date(),
187 ...(OCPP16ServiceUtils.hasReservation(
188 chargingStation,
189 commandParams?.connectorId as number,
190 commandParams?.idTag as string,
191 ) && {
192 reservationId: chargingStation.getReservationBy(
193 'connectorId',
194 chargingStation.getConnectorStatus(0)?.status === OCPP16ChargePointStatus.Reserved
195 ? 0
196 : (commandParams?.connectorId as number),
197 )!.reservationId,
198 }),
199 ...commandParams,
200 } as unknown as Request;
201 case OCPP16RequestCommand.STOP_TRANSACTION:
202 chargingStation.stationInfo?.transactionDataMeterValues &&
203 (connectorId = chargingStation.getConnectorIdByTransactionId(
204 commandParams?.transactionId as number,
205 )!);
206 energyActiveImportRegister = chargingStation.getEnergyActiveImportRegisterByTransactionId(
207 commandParams?.transactionId as number,
208 true,
209 );
210 return {
211 idTag: chargingStation.getTransactionIdTag(commandParams?.transactionId as number),
212 meterStop: energyActiveImportRegister,
213 timestamp: new Date(),
214 ...(chargingStation.stationInfo?.transactionDataMeterValues && {
215 transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
216 chargingStation.getConnectorStatus(connectorId!)!.transactionBeginMeterValue!,
217 OCPP16ServiceUtils.buildTransactionEndMeterValue(
218 chargingStation,
219 connectorId!,
220 energyActiveImportRegister,
221 ),
222 ),
223 }),
224 ...commandParams,
225 } as unknown as Request;
226 default:
227 // OCPPError usage here is debatable: it's an error in the OCPP stack but not targeted to sendError().
228 throw new OCPPError(
229 ErrorType.NOT_SUPPORTED,
230 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
231 `Unsupported OCPP command '${commandName}'`,
232 commandName,
233 commandParams,
234 );
235 }
236 }
237 }