1 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
3 import type { ValidateFunction
} from
'ajv'
4 import { secondsToMilliseconds
} from
'date-fns'
10 hasReservationExpired
,
12 } from
'../../../charging-station/index.js'
13 import { OCPPError
} from
'../../../exception/index.js'
15 type ChangeConfigurationResponse
,
16 ChargingStationEvents
,
19 type GetConfigurationResponse
,
20 type GetDiagnosticsResponse
,
22 OCPP16AuthorizationStatus
,
23 type OCPP16AuthorizeRequest
,
24 type OCPP16AuthorizeResponse
,
25 type OCPP16BootNotificationResponse
,
26 type OCPP16ChangeAvailabilityResponse
,
27 OCPP16ChargePointStatus
,
28 type OCPP16ClearChargingProfileResponse
,
29 type OCPP16DataTransferResponse
,
30 type OCPP16DiagnosticsStatusNotificationResponse
,
31 type OCPP16FirmwareStatusNotificationResponse
,
32 type OCPP16GetCompositeScheduleResponse
,
33 type OCPP16HeartbeatResponse
,
34 OCPP16IncomingRequestCommand
,
35 type OCPP16MeterValuesRequest
,
36 type OCPP16MeterValuesResponse
,
38 type OCPP16ReserveNowResponse
,
39 OCPP16StandardParametersKey
,
40 type OCPP16StartTransactionRequest
,
41 type OCPP16StartTransactionResponse
,
42 type OCPP16StatusNotificationResponse
,
43 type OCPP16StopTransactionRequest
,
44 type OCPP16StopTransactionResponse
,
45 type OCPP16TriggerMessageResponse
,
46 type OCPP16UpdateFirmwareResponse
,
48 RegistrationStatusEnumType
,
49 ReservationTerminationReason
,
51 type SetChargingProfileResponse
,
52 type UnlockConnectorResponse
53 } from
'../../../types/index.js'
54 import { Constants
, convertToInt
, isAsyncFunction
, logger
} from
'../../../utils/index.js'
55 import { OCPPResponseService
} from
'../OCPPResponseService.js'
56 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils.js'
58 const moduleName
= 'OCPP16ResponseService'
60 export class OCPP16ResponseService
extends OCPPResponseService
{
61 public incomingRequestResponsePayloadValidateFunctions
: Map
<
62 OCPP16IncomingRequestCommand
,
63 ValidateFunction
<JsonType
>
66 protected payloadValidateFunctions
: Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>
67 private readonly responseHandlers
: Map
<OCPP16RequestCommand
, ResponseHandler
>
69 public constructor () {
70 // if (new.target.name === moduleName) {
71 // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
73 super(OCPPVersion
.VERSION_16
)
74 this.responseHandlers
= new Map
<OCPP16RequestCommand
, ResponseHandler
>([
76 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
77 this.handleResponseBootNotification
.bind(this) as ResponseHandler
79 [OCPP16RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
],
80 [OCPP16RequestCommand
.AUTHORIZE
, this.handleResponseAuthorize
.bind(this) as ResponseHandler
],
82 OCPP16RequestCommand
.START_TRANSACTION
,
83 this.handleResponseStartTransaction
.bind(this) as ResponseHandler
86 OCPP16RequestCommand
.STOP_TRANSACTION
,
87 this.handleResponseStopTransaction
.bind(this) as ResponseHandler
90 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
91 this.emptyResponseHandler
.bind(this) as ResponseHandler
93 [OCPP16RequestCommand
.METER_VALUES
, this.emptyResponseHandler
],
95 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
96 this.emptyResponseHandler
.bind(this) as ResponseHandler
98 [OCPP16RequestCommand
.DATA_TRANSFER
, this.emptyResponseHandler
],
99 [OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, this.emptyResponseHandler
]
101 this.payloadValidateFunctions
= new Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>([
103 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
106 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16BootNotificationResponse
>(
107 'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
115 OCPP16RequestCommand
.HEARTBEAT
,
118 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16HeartbeatResponse
>(
119 'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
127 OCPP16RequestCommand
.AUTHORIZE
,
130 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16AuthorizeResponse
>(
131 'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
139 OCPP16RequestCommand
.START_TRANSACTION
,
142 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StartTransactionResponse
>(
143 'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
151 OCPP16RequestCommand
.STOP_TRANSACTION
,
154 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StopTransactionResponse
>(
155 'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
163 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
166 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StatusNotificationResponse
>(
167 'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
175 OCPP16RequestCommand
.METER_VALUES
,
178 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16MeterValuesResponse
>(
179 'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
187 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
190 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DiagnosticsStatusNotificationResponse
>(
191 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
199 OCPP16RequestCommand
.DATA_TRANSFER
,
202 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
203 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
211 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
214 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16FirmwareStatusNotificationResponse
>(
215 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
223 this.incomingRequestResponsePayloadValidateFunctions
= new Map
<
224 OCPP16IncomingRequestCommand
,
225 ValidateFunction
<JsonType
>
228 OCPP16IncomingRequestCommand
.RESET
,
229 this.ajvIncomingRequest
231 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
232 'assets/json-schemas/ocpp/1.6/ResetResponse.json',
240 OCPP16IncomingRequestCommand
.CLEAR_CACHE
,
241 this.ajvIncomingRequest
243 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
244 'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
252 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
253 this.ajvIncomingRequest
255 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ChangeAvailabilityResponse
>(
256 'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
264 OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
,
265 this.ajvIncomingRequest
267 OCPP16ServiceUtils
.parseJsonSchemaFile
<UnlockConnectorResponse
>(
268 'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
276 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
277 this.ajvIncomingRequest
279 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetConfigurationResponse
>(
280 'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
288 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
289 this.ajvIncomingRequest
291 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeConfigurationResponse
>(
292 'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
300 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
301 this.ajvIncomingRequest
303 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16GetCompositeScheduleResponse
>(
304 'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
312 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
313 this.ajvIncomingRequest
315 OCPP16ServiceUtils
.parseJsonSchemaFile
<SetChargingProfileResponse
>(
316 'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
324 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
325 this.ajvIncomingRequest
327 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ClearChargingProfileResponse
>(
328 'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
336 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
337 this.ajvIncomingRequest
339 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
340 'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
348 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
349 this.ajvIncomingRequest
351 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
352 'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
360 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
361 this.ajvIncomingRequest
363 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetDiagnosticsResponse
>(
364 'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
372 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
373 this.ajvIncomingRequest
375 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16TriggerMessageResponse
>(
376 'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
384 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
385 this.ajvIncomingRequest
387 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
388 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
396 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
,
397 this.ajvIncomingRequest
399 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16UpdateFirmwareResponse
>(
400 'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
408 OCPP16IncomingRequestCommand
.RESERVE_NOW
,
409 this.ajvIncomingRequest
411 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ReserveNowResponse
>(
412 'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
420 OCPP16IncomingRequestCommand
.CANCEL_RESERVATION
,
421 this.ajvIncomingRequest
423 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
424 'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
432 this.validatePayload
= this.validatePayload
.bind(this)
435 public async responseHandler
<ReqType
extends JsonType
, ResType
extends JsonType
>(
436 chargingStation
: ChargingStation
,
437 commandName
: OCPP16RequestCommand
,
439 requestPayload
: ReqType
441 if (chargingStation
.isRegistered() || commandName
=== OCPP16RequestCommand
.BOOT_NOTIFICATION
) {
443 this.responseHandlers
.has(commandName
) &&
444 OCPP16ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
)
447 this.validatePayload(chargingStation
, commandName
, payload
)
448 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
449 const responseHandler
= this.responseHandlers
.get(commandName
)!
450 if (isAsyncFunction(responseHandler
)) {
451 await responseHandler(chargingStation
, payload
, requestPayload
)
455 chargingStation
: ChargingStation
,
457 requestPayload
?: JsonType
459 )(chargingStation
, payload
, requestPayload
)
463 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
471 ErrorType
.NOT_IMPLEMENTED
,
472 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
483 ErrorType
.SECURITY_ERROR
,
484 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
488 )} while the charging station is not registered on the central server`,
495 private validatePayload (
496 chargingStation
: ChargingStation
,
497 commandName
: OCPP16RequestCommand
,
500 if (this.payloadValidateFunctions
.has(commandName
)) {
501 return this.validateResponsePayload(chargingStation
, commandName
, payload
)
504 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
509 private handleResponseBootNotification (
510 chargingStation
: ChargingStation
,
511 payload
: OCPP16BootNotificationResponse
513 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
514 chargingStation
.bootNotificationResponse
= payload
515 if (chargingStation
.isRegistered()) {
516 chargingStation
.emit(ChargingStationEvents
.registered
)
517 if (chargingStation
.inAcceptedState()) {
520 OCPP16StandardParametersKey
.HeartbeatInterval
,
521 payload
.interval
.toString(),
523 { overwrite
: true, save
: true }
527 OCPP16StandardParametersKey
.HeartBeatInterval
,
528 payload
.interval
.toString(),
530 { overwrite
: true, save
: true }
532 chargingStation
.emit(ChargingStationEvents
.accepted
)
534 } else if (chargingStation
.inRejectedState()) {
535 chargingStation
.emit(ChargingStationEvents
.rejected
)
537 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
539 }' state on the central server`
540 payload
.status === RegistrationStatusEnumType
.REJECTED
541 ? logger
.warn(logMsg
)
542 : logger
.info(logMsg
)
544 delete chargingStation
.bootNotificationResponse
546 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
552 private handleResponseAuthorize (
553 chargingStation
: ChargingStation
,
554 payload
: OCPP16AuthorizeResponse
,
555 requestPayload
: OCPP16AuthorizeRequest
557 let authorizeConnectorId
: number | undefined
558 if (chargingStation
.hasEvses
) {
559 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
561 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
562 if (connectorStatus
.authorizeIdTag
=== requestPayload
.idTag
) {
563 authorizeConnectorId
= connectorId
570 for (const connectorId
of chargingStation
.connectors
.keys()) {
573 chargingStation
.getConnectorStatus(connectorId
)?.authorizeIdTag
=== requestPayload
.idTag
575 authorizeConnectorId
= connectorId
580 if (authorizeConnectorId
!= null) {
581 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
582 const authorizeConnectorStatus
= chargingStation
.getConnectorStatus(authorizeConnectorId
)!
583 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
584 authorizeConnectorStatus
.idTagAuthorized
= true
586 `${chargingStation.logPrefix()} idTag '${
588 }' accepted on connector id ${authorizeConnectorId}`
591 authorizeConnectorStatus
.idTagAuthorized
= false
592 delete authorizeConnectorStatus
.authorizeIdTag
594 `${chargingStation.logPrefix()} idTag '${
596 }' rejected with status '${payload.idTagInfo.status}'`
601 `${chargingStation.logPrefix()} idTag '${
603 }' has no authorize request pending`
608 private async handleResponseStartTransaction (
609 chargingStation
: ChargingStation
,
610 payload
: OCPP16StartTransactionResponse
,
611 requestPayload
: OCPP16StartTransactionRequest
613 const { connectorId
} = requestPayload
614 if (connectorId
=== 0 || !chargingStation
.hasConnector(connectorId
)) {
616 `${chargingStation.logPrefix()} Trying to start a transaction on a non existing connector id ${connectorId}`
620 const connectorStatus
= chargingStation
.getConnectorStatus(connectorId
)
622 connectorStatus
?.transactionRemoteStarted
=== true &&
623 chargingStation
.getAuthorizeRemoteTxRequests() &&
624 chargingStation
.getLocalAuthListEnabled() &&
625 chargingStation
.hasIdTags() &&
626 connectorStatus
.idTagLocalAuthorized
=== false
629 `${chargingStation.logPrefix()} Trying to start a transaction with a not local authorized idTag ${
630 connectorStatus.localAuthorizeIdTag
631 } on connector id ${connectorId}`
633 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
637 connectorStatus
?.transactionRemoteStarted
=== true &&
638 chargingStation
.getAuthorizeRemoteTxRequests() &&
639 chargingStation
.stationInfo
?.remoteAuthorization
=== true &&
640 connectorStatus
.idTagLocalAuthorized
=== false &&
641 connectorStatus
.idTagAuthorized
=== false
644 `${chargingStation.logPrefix()} Trying to start a transaction with a not authorized idTag ${
645 connectorStatus.authorizeIdTag
646 } on connector id ${connectorId}`
648 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
652 connectorStatus
?.idTagAuthorized
=== true &&
653 connectorStatus
.authorizeIdTag
!= null &&
654 connectorStatus
.authorizeIdTag
!== requestPayload
.idTag
657 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
659 } different from the authorize request one ${
660 connectorStatus.authorizeIdTag
661 } on connector id ${connectorId}`
663 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
667 connectorStatus
?.idTagLocalAuthorized
=== true &&
668 connectorStatus
.localAuthorizeIdTag
!= null &&
669 connectorStatus
.localAuthorizeIdTag
!== requestPayload
.idTag
672 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
674 } different from the local authorized one ${
675 connectorStatus.localAuthorizeIdTag
676 } on connector id ${connectorId}`
678 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
681 if (connectorStatus
?.transactionStarted
=== true) {
683 `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector id ${connectorId} by idTag ${
684 connectorStatus.transactionIdTag
689 if (chargingStation
.hasEvses
) {
690 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
691 if (evseStatus
.connectors
.size
> 1) {
692 for (const [id
, status] of evseStatus
.connectors
) {
693 if (id
!== connectorId
&& status.transactionStarted
=== true) {
695 `${chargingStation.logPrefix()} Trying to start a transaction on an already used evse id ${evseId} by connector id ${id} with idTag ${
696 status.transactionIdTag
699 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
707 connectorStatus
?.status !== OCPP16ChargePointStatus
.Available
&&
708 connectorStatus
?.status !== OCPP16ChargePointStatus
.Preparing
711 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId} with status ${
712 connectorStatus?.status
717 if (!Number.isSafeInteger(payload
.transactionId
)) {
719 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId} with a non integer transaction id ${
720 payload.transactionId
721 }, converting to integer`
723 payload
.transactionId
= convertToInt(payload
.transactionId
)
726 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
727 connectorStatus
.transactionStarted
= true
728 connectorStatus
.transactionStart
= requestPayload
.timestamp
729 connectorStatus
.transactionId
= payload
.transactionId
730 connectorStatus
.transactionIdTag
= requestPayload
.idTag
731 connectorStatus
.transactionEnergyActiveImportRegisterValue
= 0
732 connectorStatus
.transactionBeginMeterValue
=
733 OCPP16ServiceUtils
.buildTransactionBeginMeterValue(
736 requestPayload
.meterStart
738 if (requestPayload
.reservationId
!= null) {
739 const reservation
= chargingStation
.getReservationBy(
741 requestPayload
.reservationId
743 if (reservation
!= null) {
744 if (reservation
.idTag
!== requestPayload
.idTag
) {
746 `${chargingStation.logPrefix()} Reserved transaction ${
747 payload.transactionId
748 } started with a different idTag ${
750 } than the reservation one ${reservation.idTag}`
753 if (hasReservationExpired(reservation
)) {
755 `${chargingStation.logPrefix()} Reserved transaction ${
756 payload.transactionId
757 } started with expired reservation ${
758 requestPayload.reservationId
759 } (expiry date: ${reservation.expiryDate.toISOString()}))`
762 await chargingStation
.removeReservation(
764 ReservationTerminationReason
.TRANSACTION_STARTED
768 `${chargingStation.logPrefix()} Reserved transaction ${
769 payload.transactionId
770 } started with unknown reservation ${requestPayload.reservationId}`
774 chargingStation
.stationInfo
?.beginEndMeterValues
=== true &&
775 (await chargingStation
.ocppRequestService
.requestHandler
<
776 OCPP16MeterValuesRequest
,
777 OCPP16MeterValuesResponse
778 >(chargingStation
, OCPP16RequestCommand
.METER_VALUES
, {
780 transactionId
: payload
.transactionId
,
781 meterValue
: [connectorStatus
.transactionBeginMeterValue
]
782 } satisfies OCPP16MeterValuesRequest
))
783 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
786 OCPP16ChargePointStatus
.Charging
789 `${chargingStation.logPrefix()} Transaction with id ${payload.transactionId} STARTED on ${
790 chargingStation.stationInfo?.chargingStationId
791 }#${connectorId} for idTag '${requestPayload.idTag}'`
793 if (chargingStation
.stationInfo
?.powerSharedByConnectors
=== true) {
794 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
795 ++chargingStation
.powerDivider
!
797 const configuredMeterValueSampleInterval
= getConfigurationKey(
799 OCPP16StandardParametersKey
.MeterValueSampleInterval
801 chargingStation
.startMeterValues(
803 configuredMeterValueSampleInterval
!= null
804 ? secondsToMilliseconds(convertToInt(configuredMeterValueSampleInterval
.value
))
805 : Constants
.DEFAULT_METER_VALUES_INTERVAL
809 `${chargingStation.logPrefix()} Starting transaction with id ${
810 payload.transactionId
812 chargingStation.stationInfo?.chargingStationId
813 }#${connectorId} with status '${payload.idTagInfo.status}', idTag '${
816 OCPP16ServiceUtils.hasReservation(chargingStation, connectorId, requestPayload.idTag)
817 ? `, reservationId
'${requestPayload.reservationId}'`
821 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
825 private async resetConnectorOnStartTransactionError (
826 chargingStation
: ChargingStation
,
829 chargingStation
.stopMeterValues(connectorId
)
830 const connectorStatus
= chargingStation
.getConnectorStatus(connectorId
)
831 resetConnectorStatus(connectorStatus
)
832 await OCPP16ServiceUtils
.restoreConnectorStatus(chargingStation
, connectorId
, connectorStatus
)
835 private async handleResponseStopTransaction (
836 chargingStation
: ChargingStation
,
837 payload
: OCPP16StopTransactionResponse
,
838 requestPayload
: OCPP16StopTransactionRequest
840 const transactionConnectorId
= chargingStation
.getConnectorIdByTransactionId(
841 requestPayload
.transactionId
843 if (transactionConnectorId
== null) {
845 `${chargingStation.logPrefix()} Trying to stop a non existing transaction with id ${
846 requestPayload.transactionId
851 chargingStation
.stationInfo
?.beginEndMeterValues
=== true &&
852 chargingStation
.stationInfo
.ocppStrictCompliance
=== false &&
853 chargingStation
.stationInfo
.outOfOrderEndMeterValues
=== true &&
854 (await chargingStation
.ocppRequestService
.requestHandler
<
855 OCPP16MeterValuesRequest
,
856 OCPP16MeterValuesResponse
857 >(chargingStation
, OCPP16RequestCommand
.METER_VALUES
, {
858 connectorId
: transactionConnectorId
,
859 transactionId
: requestPayload
.transactionId
,
861 OCPP16ServiceUtils
.buildTransactionEndMeterValue(
863 transactionConnectorId
,
864 requestPayload
.meterStop
869 !chargingStation
.isChargingStationAvailable() ||
870 !chargingStation
.isConnectorAvailable(transactionConnectorId
)
872 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
874 transactionConnectorId
,
875 OCPP16ChargePointStatus
.Unavailable
878 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
880 transactionConnectorId
,
881 OCPP16ChargePointStatus
.Available
884 if (chargingStation
.stationInfo
?.powerSharedByConnectors
=== true) {
885 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
886 chargingStation
.powerDivider
!--
888 resetConnectorStatus(chargingStation
.getConnectorStatus(transactionConnectorId
))
889 chargingStation
.stopMeterValues(transactionConnectorId
)
890 const logMsg
= `${chargingStation.logPrefix()} Transaction with id ${
891 requestPayload.transactionId
893 chargingStation.stationInfo?.chargingStationId
894 }#${transactionConnectorId} with status '${payload.idTagInfo?.status}'`
896 payload
.idTagInfo
== null ||
897 payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED