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