1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
3 import { parentPort
} from
'node:worker_threads';
5 import type { JSONSchemaType
} from
'ajv';
6 import { secondsToMilliseconds
} from
'date-fns';
8 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils';
13 hasReservationExpired
,
15 } from
'../../../charging-station';
16 import { OCPPError
} from
'../../../exception';
18 type ChangeConfigurationResponse
,
19 type ClearChargingProfileResponse
,
22 type GetConfigurationResponse
,
23 type GetDiagnosticsResponse
,
26 OCPP16AuthorizationStatus
,
27 type OCPP16AuthorizeRequest
,
28 type OCPP16AuthorizeResponse
,
29 type OCPP16BootNotificationResponse
,
30 type OCPP16ChangeAvailabilityResponse
,
31 OCPP16ChargePointStatus
,
32 type OCPP16DataTransferResponse
,
33 type OCPP16DiagnosticsStatusNotificationResponse
,
34 type OCPP16FirmwareStatusNotificationResponse
,
35 type OCPP16GetCompositeScheduleResponse
,
36 type OCPP16HeartbeatResponse
,
37 OCPP16IncomingRequestCommand
,
38 type OCPP16MeterValuesRequest
,
39 type OCPP16MeterValuesResponse
,
41 type OCPP16ReserveNowResponse
,
42 OCPP16StandardParametersKey
,
43 type OCPP16StartTransactionRequest
,
44 type OCPP16StartTransactionResponse
,
45 type OCPP16StatusNotificationResponse
,
46 type OCPP16StopTransactionRequest
,
47 type OCPP16StopTransactionResponse
,
48 type OCPP16TriggerMessageResponse
,
49 type OCPP16UpdateFirmwareResponse
,
51 RegistrationStatusEnumType
,
52 ReservationTerminationReason
,
54 type SetChargingProfileResponse
,
55 type UnlockConnectorResponse
,
56 } from
'../../../types';
63 } from
'../../../utils';
64 import { OCPPResponseService
} from
'../OCPPResponseService';
66 const moduleName
= 'OCPP16ResponseService';
68 export class OCPP16ResponseService
extends OCPPResponseService
{
69 public jsonIncomingRequestResponseSchemas
: Map
<
70 OCPP16IncomingRequestCommand
,
71 JSONSchemaType
<JsonObject
>
74 private responseHandlers
: Map
<OCPP16RequestCommand
, ResponseHandler
>;
75 private jsonSchemas
: Map
<OCPP16RequestCommand
, JSONSchemaType
<JsonObject
>>;
77 public constructor() {
78 // if (new.target?.name === moduleName) {
79 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
81 super(OCPPVersion
.VERSION_16
);
82 this.responseHandlers
= new Map
<OCPP16RequestCommand
, ResponseHandler
>([
84 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
85 this.handleResponseBootNotification
.bind(this) as ResponseHandler
,
87 [OCPP16RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
.bind(this) as ResponseHandler
],
88 [OCPP16RequestCommand
.AUTHORIZE
, this.handleResponseAuthorize
.bind(this) as ResponseHandler
],
90 OCPP16RequestCommand
.START_TRANSACTION
,
91 this.handleResponseStartTransaction
.bind(this) as ResponseHandler
,
94 OCPP16RequestCommand
.STOP_TRANSACTION
,
95 this.handleResponseStopTransaction
.bind(this) as ResponseHandler
,
98 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
99 this.emptyResponseHandler
.bind(this) as ResponseHandler
,
101 [OCPP16RequestCommand
.METER_VALUES
, this.emptyResponseHandler
.bind(this) as ResponseHandler
],
103 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
104 this.emptyResponseHandler
.bind(this) as ResponseHandler
,
106 [OCPP16RequestCommand
.DATA_TRANSFER
, this.emptyResponseHandler
.bind(this) as ResponseHandler
],
108 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
109 this.emptyResponseHandler
.bind(this) as ResponseHandler
,
112 this.jsonSchemas
= new Map
<OCPP16RequestCommand
, JSONSchemaType
<JsonObject
>>([
114 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
115 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16BootNotificationResponse
>(
116 'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
122 OCPP16RequestCommand
.HEARTBEAT
,
123 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16HeartbeatResponse
>(
124 'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
130 OCPP16RequestCommand
.AUTHORIZE
,
131 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16AuthorizeResponse
>(
132 'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
138 OCPP16RequestCommand
.START_TRANSACTION
,
139 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StartTransactionResponse
>(
140 'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
146 OCPP16RequestCommand
.STOP_TRANSACTION
,
147 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StopTransactionResponse
>(
148 'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
154 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
155 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StatusNotificationResponse
>(
156 'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
162 OCPP16RequestCommand
.METER_VALUES
,
163 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16MeterValuesResponse
>(
164 'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
170 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
171 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DiagnosticsStatusNotificationResponse
>(
172 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
178 OCPP16RequestCommand
.DATA_TRANSFER
,
179 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
180 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
186 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
187 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16FirmwareStatusNotificationResponse
>(
188 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
194 this.jsonIncomingRequestResponseSchemas
= new Map([
196 OCPP16IncomingRequestCommand
.RESET
,
197 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
198 'assets/json-schemas/ocpp/1.6/ResetResponse.json',
204 OCPP16IncomingRequestCommand
.CLEAR_CACHE
,
205 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
206 'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
212 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
213 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ChangeAvailabilityResponse
>(
214 'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
220 OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
,
221 OCPP16ServiceUtils
.parseJsonSchemaFile
<UnlockConnectorResponse
>(
222 'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
228 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
229 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetConfigurationResponse
>(
230 'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
236 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
237 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeConfigurationResponse
>(
238 'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
244 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
245 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16GetCompositeScheduleResponse
>(
246 'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
252 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
253 OCPP16ServiceUtils
.parseJsonSchemaFile
<SetChargingProfileResponse
>(
254 'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
260 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
261 OCPP16ServiceUtils
.parseJsonSchemaFile
<ClearChargingProfileResponse
>(
262 'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
268 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
269 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
270 'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
276 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
277 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
278 'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
284 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
285 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetDiagnosticsResponse
>(
286 'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
292 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
293 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16TriggerMessageResponse
>(
294 'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
300 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
301 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
302 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
308 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
,
309 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16UpdateFirmwareResponse
>(
310 'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
316 OCPP16IncomingRequestCommand
.RESERVE_NOW
,
317 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ReserveNowResponse
>(
318 'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
324 OCPP16IncomingRequestCommand
.CANCEL_RESERVATION
,
325 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
326 'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
332 this.validatePayload
= this.validatePayload
.bind(this) as (
333 chargingStation
: ChargingStation
,
334 commandName
: OCPP16RequestCommand
,
339 public async responseHandler
<ReqType
extends JsonType
, ResType
extends JsonType
>(
340 chargingStation
: ChargingStation
,
341 commandName
: OCPP16RequestCommand
,
343 requestPayload
: ReqType
,
346 chargingStation
.isRegistered() === true ||
347 commandName
=== OCPP16RequestCommand
.BOOT_NOTIFICATION
350 this.responseHandlers
.has(commandName
) === true &&
351 OCPP16ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
) === true
354 this.validatePayload(chargingStation
, commandName
, payload
);
355 await this.responseHandlers
.get(commandName
)!(chargingStation
, payload
, requestPayload
);
358 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
366 ErrorType
.NOT_IMPLEMENTED
,
367 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
378 ErrorType
.SECURITY_ERROR
,
379 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
383 )} while the charging station is not registered on the central server.`,
390 private validatePayload(
391 chargingStation
: ChargingStation
,
392 commandName
: OCPP16RequestCommand
,
395 if (this.jsonSchemas
.has(commandName
) === true) {
396 return this.validateResponsePayload(
399 this.jsonSchemas
.get(commandName
)!,
404 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`,
409 private handleResponseBootNotification(
410 chargingStation
: ChargingStation
,
411 payload
: OCPP16BootNotificationResponse
,
413 if (payload
.status === RegistrationStatusEnumType
.ACCEPTED
) {
416 OCPP16StandardParametersKey
.HeartbeatInterval
,
417 payload
.interval
.toString(),
419 { overwrite
: true, save
: true },
423 OCPP16StandardParametersKey
.HeartBeatInterval
,
424 payload
.interval
.toString(),
426 { overwrite
: true, save
: true },
428 OCPP16ServiceUtils
.startHeartbeatInterval(chargingStation
, payload
.interval
);
430 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
431 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
433 }' state on the central server`;
434 payload
.status === RegistrationStatusEnumType
.REJECTED
435 ? logger
.warn(logMsg
)
436 : logger
.info(logMsg
);
439 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
445 private handleResponseAuthorize(
446 chargingStation
: ChargingStation
,
447 payload
: OCPP16AuthorizeResponse
,
448 requestPayload
: OCPP16AuthorizeRequest
,
450 let authorizeConnectorId
: number | undefined;
451 if (chargingStation
.hasEvses
) {
452 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
454 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
455 if (connectorStatus
?.authorizeIdTag
=== requestPayload
.idTag
) {
456 authorizeConnectorId
= connectorId
;
463 for (const connectorId
of chargingStation
.connectors
.keys()) {
466 chargingStation
.getConnectorStatus(connectorId
)?.authorizeIdTag
=== requestPayload
.idTag
468 authorizeConnectorId
= connectorId
;
473 const authorizeConnectorIdDefined
= !isNullOrUndefined(authorizeConnectorId
);
474 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
475 if (authorizeConnectorIdDefined
) {
476 // chargingStation.getConnectorStatus(authorizeConnectorId!)!.authorizeIdTag =
477 // requestPayload.idTag;
478 chargingStation
.getConnectorStatus(authorizeConnectorId
!)!.idTagAuthorized
= true;
481 `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' accepted${
482 authorizeConnectorIdDefined ? ` on connector id ${authorizeConnectorId}
` : ''
486 if (authorizeConnectorIdDefined
) {
487 chargingStation
.getConnectorStatus(authorizeConnectorId
!)!.idTagAuthorized
= false;
488 delete chargingStation
.getConnectorStatus(authorizeConnectorId
!)?.authorizeIdTag
;
491 `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' rejected with status '${
492 payload.idTagInfo.status
493 }'${authorizeConnectorIdDefined ? ` on connector id ${authorizeConnectorId}` : ''}`,
498 private async handleResponseStartTransaction(
499 chargingStation: ChargingStation,
500 payload: OCPP16StartTransactionResponse,
501 requestPayload: OCPP16StartTransactionRequest,
503 const transactionConnectorId = requestPayload.connectorId;
505 transactionConnectorId === 0 ||
506 chargingStation.hasConnector(transactionConnectorId) === false
509 `${chargingStation.logPrefix()} Trying to start a transaction on a non existing connector id ${transactionConnectorId.toString()}
`,
514 chargingStation.getConnectorStatus(transactionConnectorId)?.transactionRemoteStarted ===
516 chargingStation.getAuthorizeRemoteTxRequests() === true &&
517 chargingStation.getLocalAuthListEnabled() === true &&
518 chargingStation.hasIdTags() === true &&
519 chargingStation.getConnectorStatus(transactionConnectorId)?.idTagLocalAuthorized === false
522 `${chargingStation.logPrefix()} Trying to start a transaction
with a not local authorized idTag $
{chargingStation
.getConnectorStatus(
523 transactionConnectorId
,
524 )?.localAuthorizeIdTag
} on connector id ${transactionConnectorId.toString()}
`,
526 await this.resetConnectorOnStartTransactionError(chargingStation, transactionConnectorId);
530 chargingStation.getConnectorStatus(transactionConnectorId)?.transactionRemoteStarted ===
532 chargingStation.getAuthorizeRemoteTxRequests() === true &&
533 chargingStation.getRemoteAuthorization() === true &&
534 chargingStation.getConnectorStatus(transactionConnectorId)?.idTagLocalAuthorized === false &&
535 chargingStation.getConnectorStatus(transactionConnectorId)?.idTagAuthorized === false
538 `${chargingStation.logPrefix()} Trying to start a transaction
with a not authorized idTag $
{chargingStation
.getConnectorStatus(
539 transactionConnectorId
,
540 )?.authorizeIdTag
} on connector id ${transactionConnectorId.toString()}
`,
542 await this.resetConnectorOnStartTransactionError(chargingStation, transactionConnectorId);
546 chargingStation.getConnectorStatus(transactionConnectorId)?.idTagAuthorized &&
547 chargingStation.getConnectorStatus(transactionConnectorId)?.authorizeIdTag !==
551 `${chargingStation.logPrefix()} Trying to start a transaction
with an idTag $
{
553 } different from the authorize request one $
{chargingStation
.getConnectorStatus(
554 transactionConnectorId
,
555 )?.authorizeIdTag
} on connector id ${transactionConnectorId.toString()}
`,
557 await this.resetConnectorOnStartTransactionError(chargingStation, transactionConnectorId);
561 chargingStation.getConnectorStatus(transactionConnectorId)?.idTagLocalAuthorized &&
562 chargingStation.getConnectorStatus(transactionConnectorId)?.localAuthorizeIdTag !==
566 `${chargingStation.logPrefix()} Trying to start a transaction
with an idTag $
{
568 } different from the local authorized one $
{chargingStation
.getConnectorStatus(
569 transactionConnectorId
,
570 )?.localAuthorizeIdTag
} on connector id ${transactionConnectorId.toString()}
`,
572 await this.resetConnectorOnStartTransactionError(chargingStation, transactionConnectorId);
575 if (chargingStation.getConnectorStatus(transactionConnectorId)?.transactionStarted === true) {
577 `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector id ${transactionConnectorId.toString()}
:`,
578 chargingStation.getConnectorStatus(transactionConnectorId),
582 if (chargingStation.hasEvses) {
583 for (const [evseId, evseStatus] of chargingStation.evses) {
584 if (evseStatus.connectors.size > 1) {
585 for (const [connectorId, connectorStatus] of evseStatus.connectors) {
587 transactionConnectorId !== connectorId &&
588 connectorStatus?.transactionStarted === true
591 `${chargingStation.logPrefix()} Trying to start a transaction on an already used evse id ${evseId.toString()}
:`,
594 await this.resetConnectorOnStartTransactionError(
596 transactionConnectorId,
605 chargingStation.getConnectorStatus(transactionConnectorId)?.status !==
606 OCPP16ChargePointStatus.Available &&
607 chargingStation.getConnectorStatus(transactionConnectorId)?.status !==
608 OCPP16ChargePointStatus.Preparing
611 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${transactionConnectorId.toString()}
with status $
{chargingStation
.getConnectorStatus(
612 transactionConnectorId
,
617 if (!Number.isSafeInteger(payload.transactionId)) {
619 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${transactionConnectorId.toString()}
with a non integer transaction id $
{
620 payload
.transactionId
621 }, converting to integer
`,
623 payload.transactionId = convertToInt(payload.transactionId);
626 if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
627 chargingStation.getConnectorStatus(transactionConnectorId)!.transactionStarted = true;
628 chargingStation.getConnectorStatus(transactionConnectorId)!.transactionStart =
629 requestPayload.timestamp;
630 chargingStation.getConnectorStatus(transactionConnectorId)!.transactionId =
631 payload.transactionId;
632 chargingStation.getConnectorStatus(transactionConnectorId)!.transactionIdTag =
633 requestPayload.idTag;
634 chargingStation.getConnectorStatus(
635 transactionConnectorId,
636 )!.transactionEnergyActiveImportRegisterValue = 0;
637 chargingStation.getConnectorStatus(transactionConnectorId)!.transactionBeginMeterValue =
638 OCPP16ServiceUtils.buildTransactionBeginMeterValue(
640 transactionConnectorId,
641 requestPayload.meterStart,
643 if (requestPayload.reservationId) {
644 const reservation = chargingStation.getReservationBy(
646 requestPayload.reservationId,
648 if (reservation.idTag !== requestPayload.idTag) {
650 `${chargingStation.logPrefix()} Reserved transaction $
{
651 payload
.transactionId
652 } started
with a different idTag ${requestPayload.idTag} than the reservation one $
{
657 if (hasReservationExpired(reservation)) {
659 `${chargingStation.logPrefix()} Reserved transaction $
{
660 payload
.transactionId
661 } started
with expired reservation $
{
662 requestPayload
.reservationId
663 } (expiry date
: ${reservation.expiryDate.toISOString()}
))`,
666 await chargingStation.removeReservation(
668 ReservationTerminationReason.TRANSACTION_STARTED,
671 chargingStation.getBeginEndMeterValues() &&
672 (await chargingStation.ocppRequestService.requestHandler<
673 OCPP16MeterValuesRequest,
674 OCPP16MeterValuesResponse
675 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
676 connectorId: transactionConnectorId,
677 transactionId: payload.transactionId,
679 chargingStation.getConnectorStatus(transactionConnectorId)!.transactionBeginMeterValue,
681 } as OCPP16MeterValuesRequest));
682 await OCPP16ServiceUtils.sendAndSetConnectorStatus(
684 transactionConnectorId,
685 OCPP16ChargePointStatus.Charging,
688 `${chargingStation.logPrefix()} Transaction
with id ${payload.transactionId.toString()} STARTED on $
{
689 chargingStation
.stationInfo
.chargingStationId
690 }#${transactionConnectorId.toString()}
for idTag
'${requestPayload.idTag}'`,
692 if (chargingStation.stationInfo.powerSharedByConnectors) {
693 ++chargingStation.powerDivider;
695 const configuredMeterValueSampleInterval = getConfigurationKey(
697 OCPP16StandardParametersKey.MeterValueSampleInterval,
699 chargingStation.startMeterValues(
700 transactionConnectorId,
701 configuredMeterValueSampleInterval
702 ? secondsToMilliseconds(convertToInt(configuredMeterValueSampleInterval.value))
703 : Constants.DEFAULT_METER_VALUES_INTERVAL,
707 `${chargingStation.logPrefix()} Starting transaction
with id ${payload.transactionId.toString()} REJECTED on $
{
708 chargingStation
.stationInfo
.chargingStationId
709 }#${transactionConnectorId.toString()}
with status '${payload.idTagInfo?.status}', idTag
'${
712 OCPP16ServiceUtils
.hasReservation(
714 transactionConnectorId
,
715 requestPayload
.idTag
,
717 ? `, reservationId '${requestPayload.reservationId}'`
721 await this.resetConnectorOnStartTransactionError(chargingStation, transactionConnectorId);
725 private async resetConnectorOnStartTransactionError(
726 chargingStation: ChargingStation,
729 resetConnectorStatus(chargingStation.getConnectorStatus(connectorId)!);
730 chargingStation.stopMeterValues(connectorId);
731 parentPort?.postMessage(buildUpdatedMessage(chargingStation));
733 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Available
735 await OCPP16ServiceUtils.sendAndSetConnectorStatus(
738 OCPP16ChargePointStatus.Available,
743 private async handleResponseStopTransaction(
744 chargingStation: ChargingStation,
745 payload: OCPP16StopTransactionResponse,
746 requestPayload: OCPP16StopTransactionRequest,
748 const transactionConnectorId = chargingStation.getConnectorIdByTransactionId(
749 requestPayload.transactionId,
751 if (isNullOrUndefined(transactionConnectorId)) {
753 `${chargingStation.logPrefix()} Trying to stop a non existing transaction
with id ${requestPayload.transactionId.toString()}
`,
757 chargingStation.getBeginEndMeterValues() === true &&
758 chargingStation.getOcppStrictCompliance() === false &&
759 chargingStation.getOutOfOrderEndMeterValues() === true &&
760 (await chargingStation.ocppRequestService.requestHandler<
761 OCPP16MeterValuesRequest,
762 OCPP16MeterValuesResponse
763 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
764 connectorId: transactionConnectorId,
765 transactionId: requestPayload.transactionId,
767 OCPP16ServiceUtils.buildTransactionEndMeterValue(
769 transactionConnectorId!,
770 requestPayload.meterStop,
775 chargingStation.isChargingStationAvailable() === false ||
776 chargingStation.isConnectorAvailable(transactionConnectorId!) === false
778 await OCPP16ServiceUtils.sendAndSetConnectorStatus(
780 transactionConnectorId!,
781 OCPP16ChargePointStatus.Unavailable,
784 await OCPP16ServiceUtils.sendAndSetConnectorStatus(
786 transactionConnectorId!,
787 OCPP16ChargePointStatus.Available,
790 if (chargingStation.stationInfo.powerSharedByConnectors) {
791 chargingStation.powerDivider--;
793 resetConnectorStatus(chargingStation.getConnectorStatus(transactionConnectorId!)!);
794 chargingStation.stopMeterValues(transactionConnectorId!);
795 parentPort?.postMessage(buildUpdatedMessage(chargingStation));
796 const logMsg = `${chargingStation.logPrefix()} Transaction
with id ${requestPayload.transactionId.toString()} STOPPED on $
{
797 chargingStation
.stationInfo
.chargingStationId
798 }#${transactionConnectorId?.toString()}
with status '${
799 payload.idTagInfo?.status ?? 'undefined'
802 isNullOrUndefined(payload.idTagInfo) ||
803 payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED