1 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
3 import type { ValidateFunction
} from
'ajv'
4 import { secondsToMilliseconds
} from
'date-fns'
6 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils.js'
11 hasReservationExpired
,
13 } from
'../../../charging-station/index.js'
14 import { OCPPError
} from
'../../../exception/index.js'
16 type ChangeConfigurationResponse
,
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'
57 const moduleName
= 'OCPP16ResponseService'
59 export class OCPP16ResponseService
extends OCPPResponseService
{
60 public incomingRequestResponsePayloadValidateFunctions
: Map
<
61 OCPP16IncomingRequestCommand
,
62 ValidateFunction
<JsonType
>
65 protected payloadValidateFunctions
: Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>
66 private readonly responseHandlers
: Map
<OCPP16RequestCommand
, ResponseHandler
>
68 public constructor () {
69 // if (new.target.name === moduleName) {
70 // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
72 super(OCPPVersion
.VERSION_16
)
73 this.responseHandlers
= new Map
<OCPP16RequestCommand
, ResponseHandler
>([
75 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
76 this.handleResponseBootNotification
.bind(this) as ResponseHandler
78 [OCPP16RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
],
79 [OCPP16RequestCommand
.AUTHORIZE
, this.handleResponseAuthorize
.bind(this) as ResponseHandler
],
81 OCPP16RequestCommand
.START_TRANSACTION
,
82 this.handleResponseStartTransaction
.bind(this) as ResponseHandler
85 OCPP16RequestCommand
.STOP_TRANSACTION
,
86 this.handleResponseStopTransaction
.bind(this) as ResponseHandler
89 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
90 this.emptyResponseHandler
.bind(this) as ResponseHandler
92 [OCPP16RequestCommand
.METER_VALUES
, this.emptyResponseHandler
],
94 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
95 this.emptyResponseHandler
.bind(this) as ResponseHandler
97 [OCPP16RequestCommand
.DATA_TRANSFER
, this.emptyResponseHandler
],
98 [OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, this.emptyResponseHandler
]
100 this.payloadValidateFunctions
= new Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>([
102 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
105 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16BootNotificationResponse
>(
106 'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
114 OCPP16RequestCommand
.HEARTBEAT
,
117 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16HeartbeatResponse
>(
118 'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
126 OCPP16RequestCommand
.AUTHORIZE
,
129 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16AuthorizeResponse
>(
130 'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
138 OCPP16RequestCommand
.START_TRANSACTION
,
141 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StartTransactionResponse
>(
142 'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
150 OCPP16RequestCommand
.STOP_TRANSACTION
,
153 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StopTransactionResponse
>(
154 'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
162 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
165 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StatusNotificationResponse
>(
166 'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
174 OCPP16RequestCommand
.METER_VALUES
,
177 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16MeterValuesResponse
>(
178 'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
186 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
189 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DiagnosticsStatusNotificationResponse
>(
190 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
198 OCPP16RequestCommand
.DATA_TRANSFER
,
201 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
202 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
210 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
213 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16FirmwareStatusNotificationResponse
>(
214 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
222 this.incomingRequestResponsePayloadValidateFunctions
= new Map
<
223 OCPP16IncomingRequestCommand
,
224 ValidateFunction
<JsonType
>
227 OCPP16IncomingRequestCommand
.RESET
,
228 this.ajvIncomingRequest
230 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
231 'assets/json-schemas/ocpp/1.6/ResetResponse.json',
239 OCPP16IncomingRequestCommand
.CLEAR_CACHE
,
240 this.ajvIncomingRequest
242 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
243 'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
251 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
252 this.ajvIncomingRequest
254 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ChangeAvailabilityResponse
>(
255 'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
263 OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
,
264 this.ajvIncomingRequest
266 OCPP16ServiceUtils
.parseJsonSchemaFile
<UnlockConnectorResponse
>(
267 'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
275 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
276 this.ajvIncomingRequest
278 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetConfigurationResponse
>(
279 'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
287 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
288 this.ajvIncomingRequest
290 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeConfigurationResponse
>(
291 'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
299 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
300 this.ajvIncomingRequest
302 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16GetCompositeScheduleResponse
>(
303 'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
311 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
312 this.ajvIncomingRequest
314 OCPP16ServiceUtils
.parseJsonSchemaFile
<SetChargingProfileResponse
>(
315 'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
323 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
324 this.ajvIncomingRequest
326 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ClearChargingProfileResponse
>(
327 'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
335 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
336 this.ajvIncomingRequest
338 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
339 'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
347 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
348 this.ajvIncomingRequest
350 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
351 'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
359 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
360 this.ajvIncomingRequest
362 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetDiagnosticsResponse
>(
363 'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
371 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
372 this.ajvIncomingRequest
374 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16TriggerMessageResponse
>(
375 'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
383 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
384 this.ajvIncomingRequest
386 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
387 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
395 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
,
396 this.ajvIncomingRequest
398 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16UpdateFirmwareResponse
>(
399 'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
407 OCPP16IncomingRequestCommand
.RESERVE_NOW
,
408 this.ajvIncomingRequest
410 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ReserveNowResponse
>(
411 'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
419 OCPP16IncomingRequestCommand
.CANCEL_RESERVATION
,
420 this.ajvIncomingRequest
422 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
423 'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
431 this.validatePayload
= this.validatePayload
.bind(this)
434 public async responseHandler
<ReqType
extends JsonType
, ResType
extends JsonType
>(
435 chargingStation
: ChargingStation
,
436 commandName
: OCPP16RequestCommand
,
438 requestPayload
: ReqType
440 if (chargingStation
.isRegistered() || commandName
=== OCPP16RequestCommand
.BOOT_NOTIFICATION
) {
442 this.responseHandlers
.has(commandName
) &&
443 OCPP16ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
)
446 this.validatePayload(chargingStation
, commandName
, payload
)
447 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
448 const responseHandler
= this.responseHandlers
.get(commandName
)!
449 if (isAsyncFunction(responseHandler
)) {
450 await responseHandler(chargingStation
, payload
, requestPayload
)
454 chargingStation
: ChargingStation
,
456 requestPayload
?: JsonType
458 )(chargingStation
, payload
, requestPayload
)
462 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
470 ErrorType
.NOT_IMPLEMENTED
,
471 `'${commandName}' is not implemented to handle response PDU ${JSON.stringify(
482 ErrorType
.SECURITY_ERROR
,
483 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
487 )} while the charging station is not registered on the central server`,
494 private validatePayload (
495 chargingStation
: ChargingStation
,
496 commandName
: OCPP16RequestCommand
,
499 if (this.payloadValidateFunctions
.has(commandName
)) {
500 return this.validateResponsePayload(chargingStation
, commandName
, payload
)
503 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`
508 private handleResponseBootNotification (
509 chargingStation
: ChargingStation
,
510 payload
: OCPP16BootNotificationResponse
512 if (payload
.status === RegistrationStatusEnumType
.ACCEPTED
) {
515 OCPP16StandardParametersKey
.HeartbeatInterval
,
516 payload
.interval
.toString(),
518 { overwrite
: true, save
: true }
522 OCPP16StandardParametersKey
.HeartBeatInterval
,
523 payload
.interval
.toString(),
525 { overwrite
: true, save
: true }
527 OCPP16ServiceUtils
.startHeartbeatInterval(chargingStation
, payload
.interval
)
529 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
530 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
532 }' state on the central server`
533 payload
.status === RegistrationStatusEnumType
.REJECTED
534 ? logger
.warn(logMsg
)
535 : logger
.info(logMsg
)
538 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
544 private handleResponseAuthorize (
545 chargingStation
: ChargingStation
,
546 payload
: OCPP16AuthorizeResponse
,
547 requestPayload
: OCPP16AuthorizeRequest
549 let authorizeConnectorId
: number | undefined
550 if (chargingStation
.hasEvses
) {
551 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
553 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
554 if (connectorStatus
.authorizeIdTag
=== requestPayload
.idTag
) {
555 authorizeConnectorId
= connectorId
562 for (const connectorId
of chargingStation
.connectors
.keys()) {
565 chargingStation
.getConnectorStatus(connectorId
)?.authorizeIdTag
=== requestPayload
.idTag
567 authorizeConnectorId
= connectorId
572 if (authorizeConnectorId
!= null) {
573 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
574 const authorizeConnectorStatus
= chargingStation
.getConnectorStatus(authorizeConnectorId
)!
575 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
576 authorizeConnectorStatus
.idTagAuthorized
= true
578 `${chargingStation.logPrefix()} idTag '${
580 }' accepted on connector id ${authorizeConnectorId}`
583 authorizeConnectorStatus
.idTagAuthorized
= false
584 delete authorizeConnectorStatus
.authorizeIdTag
586 `${chargingStation.logPrefix()} idTag '${requestPayload.idTag}' rejected with status '${
587 payload.idTagInfo.status
593 `${chargingStation.logPrefix()} idTag '${
595 }' has no authorize request pending`
600 private async handleResponseStartTransaction (
601 chargingStation
: ChargingStation
,
602 payload
: OCPP16StartTransactionResponse
,
603 requestPayload
: OCPP16StartTransactionRequest
605 const { connectorId
} = requestPayload
606 if (connectorId
=== 0 || !chargingStation
.hasConnector(connectorId
)) {
608 `${chargingStation.logPrefix()} Trying to start a transaction on a non existing connector id ${connectorId}`
612 const connectorStatus
= chargingStation
.getConnectorStatus(connectorId
)
614 connectorStatus
?.transactionRemoteStarted
=== true &&
615 chargingStation
.getAuthorizeRemoteTxRequests() &&
616 chargingStation
.getLocalAuthListEnabled() &&
617 chargingStation
.hasIdTags() &&
618 connectorStatus
.idTagLocalAuthorized
=== false
621 `${chargingStation.logPrefix()} Trying to start a transaction with a not local authorized idTag ${
622 connectorStatus.localAuthorizeIdTag
623 } on connector id ${connectorId}`
625 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
629 connectorStatus
?.transactionRemoteStarted
=== true &&
630 chargingStation
.getAuthorizeRemoteTxRequests() &&
631 chargingStation
.stationInfo
?.remoteAuthorization
=== true &&
632 connectorStatus
.idTagLocalAuthorized
=== false &&
633 connectorStatus
.idTagAuthorized
=== false
636 `${chargingStation.logPrefix()} Trying to start a transaction with a not authorized idTag ${
637 connectorStatus.authorizeIdTag
638 } on connector id ${connectorId}`
640 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
644 connectorStatus
?.idTagAuthorized
=== true &&
645 connectorStatus
.authorizeIdTag
!== requestPayload
.idTag
648 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
650 } different from the authorize request one ${
651 connectorStatus.authorizeIdTag
652 } on connector id ${connectorId}`
654 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
658 connectorStatus
?.idTagLocalAuthorized
=== true &&
659 connectorStatus
.localAuthorizeIdTag
!== requestPayload
.idTag
662 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
664 } different from the local authorized one ${
665 connectorStatus.localAuthorizeIdTag
666 } on connector id ${connectorId}`
668 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
671 if (connectorStatus
?.transactionStarted
=== true) {
673 `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector id ${connectorId} by idTag ${
674 connectorStatus.transactionIdTag
679 if (chargingStation
.hasEvses
) {
680 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
681 if (evseStatus
.connectors
.size
> 1) {
682 for (const [id
, status] of evseStatus
.connectors
) {
683 if (id
!== connectorId
&& status.transactionStarted
=== true) {
685 `${chargingStation.logPrefix()} Trying to start a transaction on an already used evse id ${evseId} by connector id ${id} with idTag ${
686 status.transactionIdTag
689 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
697 connectorStatus
?.status !== OCPP16ChargePointStatus
.Available
&&
698 connectorStatus
?.status !== OCPP16ChargePointStatus
.Preparing
701 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId} with status ${connectorStatus?.status}`
705 if (!Number.isSafeInteger(payload
.transactionId
)) {
707 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId} with a non integer transaction id ${
708 payload.transactionId
709 }, converting to integer`
711 payload
.transactionId
= convertToInt(payload
.transactionId
)
714 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
715 connectorStatus
.transactionStarted
= true
716 connectorStatus
.transactionStart
= requestPayload
.timestamp
717 connectorStatus
.transactionId
= payload
.transactionId
718 connectorStatus
.transactionIdTag
= requestPayload
.idTag
719 connectorStatus
.transactionEnergyActiveImportRegisterValue
= 0
720 connectorStatus
.transactionBeginMeterValue
=
721 OCPP16ServiceUtils
.buildTransactionBeginMeterValue(
724 requestPayload
.meterStart
726 if (requestPayload
.reservationId
!= null) {
727 const reservation
= chargingStation
.getReservationBy(
729 requestPayload
.reservationId
731 if (reservation
!= null) {
732 if (reservation
.idTag
!== requestPayload
.idTag
) {
734 `${chargingStation.logPrefix()} Reserved transaction ${
735 payload.transactionId
736 } started with a different idTag ${requestPayload.idTag} than the reservation one ${
741 if (hasReservationExpired(reservation
)) {
743 `${chargingStation.logPrefix()} Reserved transaction ${
744 payload.transactionId
745 } started with expired reservation ${
746 requestPayload.reservationId
747 } (expiry date: ${reservation.expiryDate.toISOString()}))`
750 await chargingStation
.removeReservation(
752 ReservationTerminationReason
.TRANSACTION_STARTED
756 `${chargingStation.logPrefix()} Reserved transaction ${
757 payload.transactionId
758 } started with unknown reservation ${requestPayload.reservationId}`
762 chargingStation
.stationInfo
?.beginEndMeterValues
=== true &&
763 (await chargingStation
.ocppRequestService
.requestHandler
<
764 OCPP16MeterValuesRequest
,
765 OCPP16MeterValuesResponse
766 >(chargingStation
, OCPP16RequestCommand
.METER_VALUES
, {
768 transactionId
: payload
.transactionId
,
769 meterValue
: [connectorStatus
.transactionBeginMeterValue
]
770 } satisfies OCPP16MeterValuesRequest
))
771 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
774 OCPP16ChargePointStatus
.Charging
777 `${chargingStation.logPrefix()} Transaction with id ${
778 payload.transactionId
779 } STARTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for idTag '${
783 if (chargingStation
.stationInfo
?.powerSharedByConnectors
=== true) {
784 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
785 ++chargingStation
.powerDivider
!
787 const configuredMeterValueSampleInterval
= getConfigurationKey(
789 OCPP16StandardParametersKey
.MeterValueSampleInterval
791 chargingStation
.startMeterValues(
793 configuredMeterValueSampleInterval
!= null
794 ? secondsToMilliseconds(convertToInt(configuredMeterValueSampleInterval
.value
))
795 : Constants
.DEFAULT_METER_VALUES_INTERVAL
799 `${chargingStation.logPrefix()} Starting transaction with id ${
800 payload.transactionId
802 chargingStation.stationInfo?.chargingStationId
803 }#${connectorId} with status '${payload.idTagInfo.status}', idTag '${
806 OCPP16ServiceUtils.hasReservation(chargingStation, connectorId, requestPayload.idTag)
807 ? `, reservationId
'${requestPayload.reservationId}'`
811 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
815 private async resetConnectorOnStartTransactionError (
816 chargingStation
: ChargingStation
,
819 const connectorStatus
= chargingStation
.getConnectorStatus(connectorId
)
820 resetConnectorStatus(connectorStatus
)
821 chargingStation
.stopMeterValues(connectorId
)
822 if (connectorStatus
?.status !== OCPP16ChargePointStatus
.Available
) {
823 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
826 OCPP16ChargePointStatus
.Available
831 private async handleResponseStopTransaction (
832 chargingStation
: ChargingStation
,
833 payload
: OCPP16StopTransactionResponse
,
834 requestPayload
: OCPP16StopTransactionRequest
836 const transactionConnectorId
= chargingStation
.getConnectorIdByTransactionId(
837 requestPayload
.transactionId
839 if (transactionConnectorId
== null) {
841 `${chargingStation.logPrefix()} Trying to stop a non existing transaction with id ${
842 requestPayload.transactionId
847 chargingStation
.stationInfo
?.beginEndMeterValues
=== true &&
848 chargingStation
.stationInfo
.ocppStrictCompliance
=== false &&
849 chargingStation
.stationInfo
.outOfOrderEndMeterValues
=== true &&
850 (await chargingStation
.ocppRequestService
.requestHandler
<
851 OCPP16MeterValuesRequest
,
852 OCPP16MeterValuesResponse
853 >(chargingStation
, OCPP16RequestCommand
.METER_VALUES
, {
854 connectorId
: transactionConnectorId
,
855 transactionId
: requestPayload
.transactionId
,
857 OCPP16ServiceUtils
.buildTransactionEndMeterValue(
859 transactionConnectorId
,
860 requestPayload
.meterStop
865 !chargingStation
.isChargingStationAvailable() ||
866 !chargingStation
.isConnectorAvailable(transactionConnectorId
)
868 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
870 transactionConnectorId
,
871 OCPP16ChargePointStatus
.Unavailable
874 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
876 transactionConnectorId
,
877 OCPP16ChargePointStatus
.Available
880 if (chargingStation
.stationInfo
?.powerSharedByConnectors
=== true) {
881 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
882 chargingStation
.powerDivider
!--
884 resetConnectorStatus(chargingStation
.getConnectorStatus(transactionConnectorId
))
885 chargingStation
.stopMeterValues(transactionConnectorId
)
886 const logMsg
= `${chargingStation.logPrefix()} Transaction with id ${
887 requestPayload.transactionId
889 chargingStation.stationInfo?.chargingStationId
890 }#${transactionConnectorId} with status '${payload.idTagInfo?.status}'`
892 payload
.idTagInfo
== null ||
893 payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED