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