refactor: remove unneeded intermediate variable in id tags cache code
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ResponseService.ts
CommitLineData
edd13439 1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
c8eeb62b 2
6c1761d4 3import type { JSONSchemaType } from 'ajv';
844e496b 4
2896e06d 5import { type ChargingStation, ChargingStationConfigurationUtils } from '../../../charging-station';
268a74bb 6import { OCPPError } from '../../../exception';
ef6fa3fb 7import {
268a74bb
JB
8 type ChangeAvailabilityResponse,
9 type ChangeConfigurationResponse,
10 type ClearChargingProfileResponse,
11 ErrorType,
12 type GenericResponse,
13 type GetConfigurationResponse,
14 type GetDiagnosticsResponse,
15 type JsonObject,
16 type JsonType,
8114d10e 17 OCPP16AuthorizationStatus,
27782dbc
JB
18 type OCPP16AuthorizeRequest,
19 type OCPP16AuthorizeResponse,
268a74bb
JB
20 type OCPP16BootNotificationRequest,
21 type OCPP16BootNotificationResponse,
22 OCPP16ChargePointErrorCode,
23 OCPP16ChargePointStatus,
24 type OCPP16DataTransferResponse,
25 type OCPP16DiagnosticsStatusNotificationResponse,
26 type OCPP16FirmwareStatusNotificationResponse,
27 type OCPP16HeartbeatResponse,
28 OCPP16IncomingRequestCommand,
29 type OCPP16MeterValuesRequest,
30 type OCPP16MeterValuesResponse,
31 OCPP16RequestCommand,
32 OCPP16StandardParametersKey,
27782dbc
JB
33 type OCPP16StartTransactionRequest,
34 type OCPP16StartTransactionResponse,
268a74bb
JB
35 type OCPP16StatusNotificationRequest,
36 type OCPP16StatusNotificationResponse,
27782dbc
JB
37 type OCPP16StopTransactionRequest,
38 type OCPP16StopTransactionResponse,
268a74bb
JB
39 type OCPP16TriggerMessageResponse,
40 type OCPP16UpdateFirmwareResponse,
41 OCPPVersion,
02887891
JB
42 RegistrationStatusEnumType,
43 type ResponseHandler,
268a74bb
JB
44 type SetChargingProfileResponse,
45 type UnlockConnectorResponse,
46} from '../../../types';
60a74391 47import { Constants, Utils, logger } from '../../../utils';
2896e06d 48import { OCPP16ServiceUtils, OCPPResponseService } from '../internal';
c0560973 49
909dcf2d
JB
50const moduleName = 'OCPP16ResponseService';
51
268a74bb 52export class OCPP16ResponseService extends OCPPResponseService {
b3fc3ff5
JB
53 public jsonIncomingRequestResponseSchemas: Map<
54 OCPP16IncomingRequestCommand,
55 JSONSchemaType<JsonObject>
56 >;
57
58144adb 58 private responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>;
b52c969d 59 private jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>;
58144adb 60
08f130a0 61 public constructor() {
b768993d
JB
62 // if (new.target?.name === moduleName) {
63 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
64 // }
d270cc87 65 super(OCPPVersion.VERSION_16);
58144adb
JB
66 this.responseHandlers = new Map<OCPP16RequestCommand, ResponseHandler>([
67 [OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)],
b52c969d 68 [OCPP16RequestCommand.HEARTBEAT, this.emptyResponseHandler.bind(this)],
58144adb
JB
69 [OCPP16RequestCommand.AUTHORIZE, this.handleResponseAuthorize.bind(this)],
70 [OCPP16RequestCommand.START_TRANSACTION, this.handleResponseStartTransaction.bind(this)],
71 [OCPP16RequestCommand.STOP_TRANSACTION, this.handleResponseStopTransaction.bind(this)],
b52c969d
JB
72 [OCPP16RequestCommand.STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
73 [OCPP16RequestCommand.METER_VALUES, this.emptyResponseHandler.bind(this)],
74 [OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
91a7d3ea 75 [OCPP16RequestCommand.DATA_TRANSFER, this.emptyResponseHandler.bind(this)],
c9a4f9ea 76 [OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
b52c969d
JB
77 ]);
78 this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>([
79 [
80 OCPP16RequestCommand.BOOT_NOTIFICATION,
130783a7 81 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationResponse>(
1b271a54
JB
82 '../../../assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
83 moduleName,
84 'constructor'
e9a4164c 85 ),
b52c969d
JB
86 ],
87 [
88 OCPP16RequestCommand.HEARTBEAT,
130783a7 89 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatResponse>(
1b271a54
JB
90 '../../../assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
91 moduleName,
92 'constructor'
e9a4164c 93 ),
b52c969d
JB
94 ],
95 [
96 OCPP16RequestCommand.AUTHORIZE,
130783a7 97 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeResponse>(
1b271a54
JB
98 '../../../assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
99 moduleName,
100 'constructor'
e9a4164c 101 ),
b52c969d
JB
102 ],
103 [
104 OCPP16RequestCommand.START_TRANSACTION,
130783a7 105 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionResponse>(
1b271a54
JB
106 '../../../assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
107 moduleName,
108 'constructor'
e9a4164c 109 ),
b52c969d
JB
110 ],
111 [
112 OCPP16RequestCommand.STOP_TRANSACTION,
130783a7 113 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionResponse>(
1b271a54
JB
114 '../../../assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
115 moduleName,
116 'constructor'
e9a4164c 117 ),
b52c969d
JB
118 ],
119 [
120 OCPP16RequestCommand.STATUS_NOTIFICATION,
130783a7 121 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationResponse>(
1b271a54
JB
122 '../../../assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
123 moduleName,
124 'constructor'
e9a4164c 125 ),
b52c969d
JB
126 ],
127 [
128 OCPP16RequestCommand.METER_VALUES,
130783a7 129 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesResponse>(
1b271a54
JB
130 '../../../assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
131 moduleName,
132 'constructor'
e9a4164c 133 ),
b52c969d
JB
134 ],
135 [
136 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
130783a7 137 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationResponse>(
1b271a54
JB
138 '../../../assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
139 moduleName,
140 'constructor'
e9a4164c 141 ),
b52c969d 142 ],
91a7d3ea
JB
143 [
144 OCPP16RequestCommand.DATA_TRANSFER,
130783a7 145 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
1b271a54
JB
146 '../../../assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
147 moduleName,
148 'constructor'
e9a4164c 149 ),
91a7d3ea 150 ],
c9a4f9ea
JB
151 [
152 OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
130783a7 153 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationResponse>(
1b271a54
JB
154 '../../../assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
155 moduleName,
156 'constructor'
e9a4164c 157 ),
c9a4f9ea 158 ],
58144adb 159 ]);
02887891
JB
160 this.jsonIncomingRequestResponseSchemas = new Map([
161 [
162 OCPP16IncomingRequestCommand.RESET,
130783a7 163 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
164 '../../../assets/json-schemas/ocpp/1.6/ResetResponse.json',
165 moduleName,
166 'constructor'
e9a4164c 167 ),
02887891
JB
168 ],
169 [
170 OCPP16IncomingRequestCommand.CLEAR_CACHE,
130783a7 171 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
172 '../../../assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
173 moduleName,
174 'constructor'
e9a4164c 175 ),
02887891
JB
176 ],
177 [
178 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
130783a7 179 OCPP16ServiceUtils.parseJsonSchemaFile<ChangeAvailabilityResponse>(
1b271a54
JB
180 '../../../assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
181 moduleName,
182 'constructor'
e9a4164c 183 ),
02887891
JB
184 ],
185 [
186 OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
130783a7 187 OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorResponse>(
1b271a54
JB
188 '../../../assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
189 moduleName,
190 'constructor'
e9a4164c 191 ),
02887891
JB
192 ],
193 [
194 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
130783a7 195 OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationResponse>(
1b271a54
JB
196 '../../../assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
197 moduleName,
198 'constructor'
e9a4164c 199 ),
02887891
JB
200 ],
201 [
202 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
130783a7 203 OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationResponse>(
1b271a54
JB
204 '../../../assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
205 moduleName,
206 'constructor'
e9a4164c 207 ),
02887891
JB
208 ],
209 [
210 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
130783a7 211 OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileResponse>(
1b271a54
JB
212 '../../../assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
213 moduleName,
214 'constructor'
e9a4164c 215 ),
02887891
JB
216 ],
217 [
218 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
130783a7 219 OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileResponse>(
1b271a54
JB
220 '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
221 moduleName,
222 'constructor'
e9a4164c 223 ),
02887891
JB
224 ],
225 [
226 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
130783a7 227 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
228 '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
229 moduleName,
230 'constructor'
e9a4164c 231 ),
02887891
JB
232 ],
233 [
234 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
130783a7 235 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
236 '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
237 moduleName,
238 'constructor'
e9a4164c 239 ),
02887891
JB
240 ],
241 [
242 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
130783a7 243 OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsResponse>(
1b271a54
JB
244 '../../../assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
245 moduleName,
246 'constructor'
e9a4164c 247 ),
02887891
JB
248 ],
249 [
250 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
130783a7 251 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageResponse>(
1b271a54
JB
252 '../../../assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
253 moduleName,
254 'constructor'
e9a4164c 255 ),
02887891
JB
256 ],
257 [
258 OCPP16IncomingRequestCommand.DATA_TRANSFER,
130783a7 259 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
1b271a54
JB
260 '../../../assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
261 moduleName,
262 'constructor'
e9a4164c 263 ),
02887891
JB
264 ],
265 [
266 OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
130783a7 267 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareResponse>(
1b271a54
JB
268 '../../../assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
269 moduleName,
270 'constructor'
e9a4164c 271 ),
02887891
JB
272 ],
273 ]);
9952c548 274 this.validatePayload.bind(this);
58144adb
JB
275 }
276
f7f98c68 277 public async responseHandler(
08f130a0 278 chargingStation: ChargingStation,
e7aeea18 279 commandName: OCPP16RequestCommand,
5cc4b63b
JB
280 payload: JsonType,
281 requestPayload: JsonType
e7aeea18 282 ): Promise<void> {
ed6cfcff
JB
283 if (
284 chargingStation.isRegistered() === true ||
285 commandName === OCPP16RequestCommand.BOOT_NOTIFICATION
286 ) {
65554cc3 287 if (
ed6cfcff
JB
288 this.responseHandlers.has(commandName) === true &&
289 OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName) === true
65554cc3 290 ) {
124f3553 291 try {
9c5c4195 292 this.validatePayload(chargingStation, commandName, payload);
08f130a0 293 await this.responseHandlers.get(commandName)(chargingStation, payload, requestPayload);
124f3553 294 } catch (error) {
6c8f5d90
JB
295 logger.error(
296 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
297 error
298 );
124f3553
JB
299 throw error;
300 }
301 } else {
302 // Throw exception
e7aeea18
JB
303 throw new OCPPError(
304 ErrorType.NOT_IMPLEMENTED,
6c8f5d90 305 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
e7aeea18
JB
306 payload,
307 null,
308 2
309 )}`,
7369e417
JB
310 commandName,
311 payload
e7aeea18 312 );
887fef76 313 }
c0560973 314 } else {
e7aeea18
JB
315 throw new OCPPError(
316 ErrorType.SECURITY_ERROR,
6c8f5d90 317 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
e7aeea18
JB
318 payload,
319 null,
320 2
439fc71b 321 )} while the charging station is not registered on the central server.`,
7369e417
JB
322 commandName,
323 payload
e7aeea18 324 );
c0560973
JB
325 }
326 }
327
9c5c4195
JB
328 private validatePayload(
329 chargingStation: ChargingStation,
330 commandName: OCPP16RequestCommand,
331 payload: JsonType
332 ): boolean {
45988780 333 if (this.jsonSchemas.has(commandName) === true) {
9c5c4195
JB
334 return this.validateResponsePayload(
335 chargingStation,
336 commandName,
337 this.jsonSchemas.get(commandName),
338 payload
339 );
340 }
341 logger.warn(
b3fc3ff5 342 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
9c5c4195
JB
343 );
344 return false;
345 }
346
08f130a0
JB
347 private handleResponseBootNotification(
348 chargingStation: ChargingStation,
349 payload: OCPP16BootNotificationResponse
350 ): void {
d270cc87 351 if (payload.status === RegistrationStatusEnumType.ACCEPTED) {
17ac262c
JB
352 ChargingStationConfigurationUtils.addConfigurationKey(
353 chargingStation,
f0f65a62 354 OCPP16StandardParametersKey.HeartbeatInterval,
a95873d8 355 payload.interval.toString(),
abe9e9dd 356 {},
a95873d8 357 { overwrite: true, save: true }
e7aeea18 358 );
17ac262c
JB
359 ChargingStationConfigurationUtils.addConfigurationKey(
360 chargingStation,
f0f65a62 361 OCPP16StandardParametersKey.HeartBeatInterval,
e7aeea18 362 payload.interval.toString(),
00db15b8 363 { visible: false },
a95873d8 364 { overwrite: true, save: true }
e7aeea18 365 );
8f953431 366 OCPP16ServiceUtils.startHeartbeatInterval(chargingStation, payload.interval);
672fed6e 367 }
d270cc87 368 if (Object.values(RegistrationStatusEnumType).includes(payload.status)) {
08f130a0 369 const logMsg = `${chargingStation.logPrefix()} Charging station in '${
e7aeea18
JB
370 payload.status
371 }' state on the central server`;
d270cc87 372 payload.status === RegistrationStatusEnumType.REJECTED
e7aeea18
JB
373 ? logger.warn(logMsg)
374 : logger.info(logMsg);
c0560973 375 } else {
e7aeea18 376 logger.error(
44eb6026 377 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
e7aeea18
JB
378 payload
379 );
c0560973
JB
380 }
381 }
382
e7aeea18 383 private handleResponseAuthorize(
08f130a0 384 chargingStation: ChargingStation,
e7aeea18 385 payload: OCPP16AuthorizeResponse,
ef6fa3fb 386 requestPayload: OCPP16AuthorizeRequest
e7aeea18 387 ): void {
58144adb 388 let authorizeConnectorId: number;
08f130a0 389 for (const connectorId of chargingStation.connectors.keys()) {
e7aeea18
JB
390 if (
391 connectorId > 0 &&
08f130a0 392 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag
e7aeea18 393 ) {
734d790d 394 authorizeConnectorId = connectorId;
58144adb
JB
395 break;
396 }
397 }
44eb6026 398 const authorizeConnectorIdDefined = authorizeConnectorId !== undefined;
58144adb 399 if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
44eb6026 400 authorizeConnectorIdDefined &&
1984f194 401 (chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true);
e7aeea18 402 logger.debug(
1984f194 403 `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' accepted${
44eb6026 404 authorizeConnectorIdDefined ? ` on connector ${authorizeConnectorId}` : ''
1984f194 405 }`
e7aeea18 406 );
58144adb 407 } else {
44eb6026 408 if (authorizeConnectorIdDefined) {
1984f194 409 chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false;
d812bdcb 410 delete chargingStation.getConnectorStatus(authorizeConnectorId)?.authorizeIdTag;
1984f194 411 }
e7aeea18 412 logger.debug(
1984f194 413 `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' rejected with status '${
e7aeea18 414 payload.idTagInfo.status
44eb6026 415 }'${authorizeConnectorIdDefined ? ` on connector ${authorizeConnectorId}` : ''}`
e7aeea18 416 );
58144adb
JB
417 }
418 }
419
e7aeea18 420 private async handleResponseStartTransaction(
08f130a0 421 chargingStation: ChargingStation,
e7aeea18 422 payload: OCPP16StartTransactionResponse,
ef6fa3fb 423 requestPayload: OCPP16StartTransactionRequest
e7aeea18 424 ): Promise<void> {
c0560973
JB
425 const connectorId = requestPayload.connectorId;
426
427 let transactionConnectorId: number;
08f130a0 428 for (const id of chargingStation.connectors.keys()) {
734d790d
JB
429 if (id > 0 && id === connectorId) {
430 transactionConnectorId = id;
c0560973
JB
431 break;
432 }
433 }
72092cfc 434 if (Utils.isNullOrUndefined(transactionConnectorId)) {
e7aeea18 435 logger.error(
44eb6026 436 `${chargingStation.logPrefix()} Trying to start a transaction on a non existing connector Id ${connectorId.toString()}`
e7aeea18 437 );
c0560973
JB
438 return;
439 }
e7aeea18 440 if (
72092cfc 441 chargingStation.getConnectorStatus(connectorId)?.transactionRemoteStarted === true &&
3a13fc92
JB
442 chargingStation.getAuthorizeRemoteTxRequests() === true &&
443 chargingStation.getLocalAuthListEnabled() === true &&
f911a4af 444 chargingStation.hasIdTags() &&
72092cfc 445 chargingStation.getConnectorStatus(connectorId)?.idTagLocalAuthorized === false
e7aeea18
JB
446 ) {
447 logger.error(
44eb6026 448 `${chargingStation.logPrefix()} Trying to start a transaction with a not local authorized idTag ${
72092cfc 449 chargingStation.getConnectorStatus(connectorId)?.localAuthorizeIdTag
44eb6026 450 } on connector Id ${connectorId.toString()}`
e7aeea18 451 );
08f130a0 452 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
453 return;
454 }
e7aeea18 455 if (
72092cfc 456 chargingStation.getConnectorStatus(connectorId)?.transactionRemoteStarted === true &&
3a13fc92
JB
457 chargingStation.getAuthorizeRemoteTxRequests() === true &&
458 chargingStation.getMustAuthorizeAtRemoteStart() === true &&
72092cfc
JB
459 chargingStation.getConnectorStatus(connectorId)?.idTagLocalAuthorized === false &&
460 chargingStation.getConnectorStatus(connectorId)?.idTagAuthorized === false
e7aeea18
JB
461 ) {
462 logger.error(
44eb6026 463 `${chargingStation.logPrefix()} Trying to start a transaction with a not authorized idTag ${
72092cfc 464 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag
44eb6026 465 } on connector Id ${connectorId.toString()}`
e7aeea18 466 );
08f130a0 467 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
468 return;
469 }
e7aeea18 470 if (
72092cfc
JB
471 chargingStation.getConnectorStatus(connectorId)?.idTagAuthorized &&
472 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag !== requestPayload.idTag
e7aeea18
JB
473 ) {
474 logger.error(
44eb6026
JB
475 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
476 requestPayload.idTag
477 } different from the authorize request one ${
72092cfc 478 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag
44eb6026 479 } on connector Id ${connectorId.toString()}`
e7aeea18 480 );
08f130a0 481 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
482 return;
483 }
e7aeea18 484 if (
72092cfc
JB
485 chargingStation.getConnectorStatus(connectorId)?.idTagLocalAuthorized &&
486 chargingStation.getConnectorStatus(connectorId)?.localAuthorizeIdTag !== requestPayload.idTag
e7aeea18
JB
487 ) {
488 logger.error(
44eb6026
JB
489 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
490 requestPayload.idTag
491 } different from the local authorized one ${
72092cfc 492 chargingStation.getConnectorStatus(connectorId)?.localAuthorizeIdTag
44eb6026 493 } on connector Id ${connectorId.toString()}`
e7aeea18 494 );
08f130a0 495 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
163547b1
JB
496 return;
497 }
5e3cb728 498 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
e7aeea18 499 logger.debug(
44eb6026 500 `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector ${connectorId.toString()}: %j`,
08f130a0 501 chargingStation.getConnectorStatus(connectorId)
e7aeea18 502 );
c0560973
JB
503 return;
504 }
e7aeea18 505 if (
08f130a0 506 chargingStation.getConnectorStatus(connectorId)?.status !==
721646e9
JB
507 OCPP16ChargePointStatus.Available &&
508 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Preparing
e7aeea18
JB
509 ) {
510 logger.error(
08f130a0
JB
511 `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${
512 chargingStation.getConnectorStatus(connectorId)?.status
e7aeea18
JB
513 }`
514 );
290d006c
JB
515 return;
516 }
fc040c43
JB
517 // if (!Number.isInteger(payload.transactionId)) {
518 // logger.warn(
519 // `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${
520 // payload.transactionId
521 // }, converting to integer`
522 // );
523 // payload.transactionId = Utils.convertToInt(payload.transactionId);
524 // }
c0560973 525
f0c6ed89 526 if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
08f130a0
JB
527 chargingStation.getConnectorStatus(connectorId).transactionStarted = true;
528 chargingStation.getConnectorStatus(connectorId).transactionId = payload.transactionId;
529 chargingStation.getConnectorStatus(connectorId).transactionIdTag = requestPayload.idTag;
530 chargingStation.getConnectorStatus(
e7aeea18
JB
531 connectorId
532 ).transactionEnergyActiveImportRegisterValue = 0;
08f130a0 533 chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue =
e7aeea18 534 OCPP16ServiceUtils.buildTransactionBeginMeterValue(
08f130a0 535 chargingStation,
e7aeea18
JB
536 connectorId,
537 requestPayload.meterStart
538 );
08f130a0
JB
539 chargingStation.getBeginEndMeterValues() &&
540 (await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
541 OCPP16MeterValuesRequest,
542 OCPP16MeterValuesResponse
08f130a0 543 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
93b4a429 544 connectorId,
ef6fa3fb 545 transactionId: payload.transactionId,
7369e417 546 meterValue: [chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue],
ef6fa3fb 547 }));
08f130a0 548 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
549 OCPP16StatusNotificationRequest,
550 OCPP16StatusNotificationResponse
08f130a0 551 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 552 connectorId,
721646e9 553 status: OCPP16ChargePointStatus.Charging,
ef6fa3fb
JB
554 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
555 });
721646e9 556 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Charging;
e7aeea18 557 logger.info(
44eb6026
JB
558 `${chargingStation.logPrefix()} Transaction ${payload.transactionId.toString()} STARTED on ${
559 chargingStation.stationInfo.chargingStationId
560 }#${connectorId.toString()} for idTag '${requestPayload.idTag}'`
e7aeea18 561 );
08f130a0 562 if (chargingStation.stationInfo.powerSharedByConnectors) {
fa7bccf4 563 chargingStation.powerDivider++;
c0560973 564 }
17ac262c
JB
565 const configuredMeterValueSampleInterval =
566 ChargingStationConfigurationUtils.getConfigurationKey(
567 chargingStation,
568 OCPP16StandardParametersKey.MeterValueSampleInterval
569 );
08f130a0 570 chargingStation.startMeterValues(
e7aeea18
JB
571 connectorId,
572 configuredMeterValueSampleInterval
573 ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000
d3195f0a 574 : Constants.DEFAULT_METER_VALUES_INTERVAL
e7aeea18 575 );
c0560973 576 } else {
e7aeea18 577 logger.warn(
44eb6026
JB
578 `${chargingStation.logPrefix()} Starting transaction id ${payload.transactionId.toString()} REJECTED with status '${
579 payload.idTagInfo?.status
580 }', idTag '${requestPayload.idTag}'`
e7aeea18 581 );
08f130a0 582 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
583 }
584 }
585
08f130a0
JB
586 private async resetConnectorOnStartTransactionError(
587 chargingStation: ChargingStation,
588 connectorId: number
589 ): Promise<void> {
590 chargingStation.resetConnectorStatus(connectorId);
e7aeea18 591 if (
721646e9 592 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Available
e7aeea18 593 ) {
08f130a0 594 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
595 OCPP16StatusNotificationRequest,
596 OCPP16StatusNotificationResponse
08f130a0 597 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 598 connectorId,
721646e9 599 status: OCPP16ChargePointStatus.Available,
ef6fa3fb
JB
600 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
601 });
721646e9 602 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Available;
c0560973
JB
603 }
604 }
605
e7aeea18 606 private async handleResponseStopTransaction(
08f130a0 607 chargingStation: ChargingStation,
e7aeea18 608 payload: OCPP16StopTransactionResponse,
ef6fa3fb 609 requestPayload: OCPP16StopTransactionRequest
e7aeea18 610 ): Promise<void> {
08f130a0 611 const transactionConnectorId = chargingStation.getConnectorIdByTransactionId(
f479a792
JB
612 requestPayload.transactionId
613 );
d812bdcb 614 if (Utils.isNullOrUndefined(transactionConnectorId)) {
e7aeea18 615 logger.error(
44eb6026 616 `${chargingStation.logPrefix()} Trying to stop a non existing transaction ${requestPayload.transactionId.toString()}`
e7aeea18 617 );
c0560973
JB
618 return;
619 }
2cace1a5
JB
620 chargingStation.getBeginEndMeterValues() === true &&
621 chargingStation.getOcppStrictCompliance() === false &&
622 chargingStation.getOutOfOrderEndMeterValues() === true &&
623 (await chargingStation.ocppRequestService.requestHandler<
624 OCPP16MeterValuesRequest,
625 OCPP16MeterValuesResponse
626 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
627 connectorId: transactionConnectorId,
628 transactionId: requestPayload.transactionId,
629 meterValue: [
630 OCPP16ServiceUtils.buildTransactionEndMeterValue(
631 chargingStation,
632 transactionConnectorId,
633 requestPayload.meterStop
634 ),
635 ],
636 }));
637 if (
638 chargingStation.isChargingStationAvailable() === false ||
639 chargingStation.isConnectorAvailable(transactionConnectorId) === false
640 ) {
641 await chargingStation.ocppRequestService.requestHandler<
642 OCPP16StatusNotificationRequest,
643 OCPP16StatusNotificationResponse
644 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
645 connectorId: transactionConnectorId,
721646e9 646 status: OCPP16ChargePointStatus.Unavailable,
2cace1a5
JB
647 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
648 });
649 chargingStation.getConnectorStatus(transactionConnectorId).status =
721646e9 650 OCPP16ChargePointStatus.Unavailable;
c0560973 651 } else {
2cace1a5
JB
652 await chargingStation.ocppRequestService.requestHandler<
653 OCPP16BootNotificationRequest,
654 OCPP16BootNotificationResponse
655 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
656 connectorId: transactionConnectorId,
721646e9 657 status: OCPP16ChargePointStatus.Available,
2cace1a5
JB
658 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
659 });
660 chargingStation.getConnectorStatus(transactionConnectorId).status =
721646e9 661 OCPP16ChargePointStatus.Available;
2cace1a5
JB
662 }
663 if (chargingStation.stationInfo.powerSharedByConnectors) {
664 chargingStation.powerDivider--;
665 }
666 chargingStation.resetConnectorStatus(transactionConnectorId);
8ca6874c
JB
667 const logMsg = `${chargingStation.logPrefix()} Transaction ${requestPayload.transactionId.toString()} STOPPED on ${
668 chargingStation.stationInfo.chargingStationId
d812bdcb 669 }#${transactionConnectorId?.toString()} with status '${
8ca6874c
JB
670 payload.idTagInfo?.status ?? 'undefined'
671 }'`;
2cace1a5
JB
672 if (
673 Utils.isNullOrUndefined(payload.idTagInfo) ||
674 payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED
675 ) {
676 logger.info(logMsg);
677 } else {
678 logger.warn(logMsg);
c0560973
JB
679 }
680 }
c0560973 681}