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