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