1 // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
3 import type { ValidateFunction
} from
'ajv'
5 import { secondsToMilliseconds
} from
'date-fns'
11 hasReservationExpired
,
13 } from
'../../../charging-station/index.js'
14 import { OCPPError
} from
'../../../exception/index.js'
16 type ChangeConfigurationResponse
,
17 ChargingStationEvents
,
20 type GetConfigurationResponse
,
21 type GetDiagnosticsResponse
,
23 OCPP16AuthorizationStatus
,
24 type OCPP16AuthorizeRequest
,
25 type OCPP16AuthorizeResponse
,
26 type OCPP16BootNotificationResponse
,
27 type OCPP16ChangeAvailabilityResponse
,
28 OCPP16ChargePointStatus
,
29 type OCPP16ClearChargingProfileResponse
,
30 type OCPP16DataTransferResponse
,
31 type OCPP16DiagnosticsStatusNotificationResponse
,
32 type OCPP16FirmwareStatusNotificationResponse
,
33 type OCPP16GetCompositeScheduleResponse
,
34 type OCPP16HeartbeatResponse
,
35 OCPP16IncomingRequestCommand
,
36 type OCPP16MeterValuesRequest
,
37 type OCPP16MeterValuesResponse
,
39 type OCPP16ReserveNowResponse
,
40 OCPP16StandardParametersKey
,
41 type OCPP16StartTransactionRequest
,
42 type OCPP16StartTransactionResponse
,
43 type OCPP16StatusNotificationResponse
,
44 type OCPP16StopTransactionRequest
,
45 type OCPP16StopTransactionResponse
,
46 type OCPP16TriggerMessageResponse
,
47 type OCPP16UpdateFirmwareResponse
,
49 RegistrationStatusEnumType
,
50 ReservationTerminationReason
,
52 type SetChargingProfileResponse
,
53 type UnlockConnectorResponse
,
54 } from
'../../../types/index.js'
55 import { Constants
, convertToInt
, isAsyncFunction
, logger
} from
'../../../utils/index.js'
56 import { OCPPResponseService
} from
'../OCPPResponseService.js'
57 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils.js'
59 const moduleName
= 'OCPP16ResponseService'
61 export class OCPP16ResponseService
extends OCPPResponseService
{
62 public incomingRequestResponsePayloadValidateFunctions
: Map
<
63 OCPP16IncomingRequestCommand
,
64 ValidateFunction
<JsonType
>
67 protected payloadValidateFunctions
: Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>
68 private readonly responseHandlers
: Map
<OCPP16RequestCommand
, ResponseHandler
>
70 public constructor () {
71 // if (new.target.name === moduleName) {
72 // throw new TypeError(`Cannot construct ${new.target.name} instances directly`)
74 super(OCPPVersion
.VERSION_16
)
75 this.responseHandlers
= new Map
<OCPP16RequestCommand
, ResponseHandler
>([
76 [OCPP16RequestCommand
.AUTHORIZE
, this.handleResponseAuthorize
.bind(this) as ResponseHandler
],
78 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
79 this.handleResponseBootNotification
.bind(this) as ResponseHandler
,
81 [OCPP16RequestCommand
.DATA_TRANSFER
, this.emptyResponseHandler
],
83 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
84 this.emptyResponseHandler
.bind(this) as ResponseHandler
,
86 [OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, this.emptyResponseHandler
],
87 [OCPP16RequestCommand
.HEARTBEAT
, this.emptyResponseHandler
],
88 [OCPP16RequestCommand
.METER_VALUES
, this.emptyResponseHandler
],
90 OCPP16RequestCommand
.START_TRANSACTION
,
91 this.handleResponseStartTransaction
.bind(this) as ResponseHandler
,
94 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
95 this.emptyResponseHandler
.bind(this) as ResponseHandler
,
98 OCPP16RequestCommand
.STOP_TRANSACTION
,
99 this.handleResponseStopTransaction
.bind(this) as ResponseHandler
,
102 this.payloadValidateFunctions
= new Map
<OCPP16RequestCommand
, ValidateFunction
<JsonType
>>([
104 OCPP16RequestCommand
.AUTHORIZE
,
106 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16AuthorizeResponse
>(
107 'assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
114 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
116 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16BootNotificationResponse
>(
117 'assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
124 OCPP16RequestCommand
.DATA_TRANSFER
,
126 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
127 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
134 OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
,
136 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DiagnosticsStatusNotificationResponse
>(
137 'assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
144 OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
,
146 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16FirmwareStatusNotificationResponse
>(
147 'assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
154 OCPP16RequestCommand
.HEARTBEAT
,
156 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16HeartbeatResponse
>(
157 'assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
164 OCPP16RequestCommand
.METER_VALUES
,
166 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16MeterValuesResponse
>(
167 'assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
174 OCPP16RequestCommand
.START_TRANSACTION
,
176 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StartTransactionResponse
>(
177 'assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
184 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
186 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StatusNotificationResponse
>(
187 'assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
194 OCPP16RequestCommand
.STOP_TRANSACTION
,
196 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16StopTransactionResponse
>(
197 'assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
204 this.incomingRequestResponsePayloadValidateFunctions
= new Map
<
205 OCPP16IncomingRequestCommand
,
206 ValidateFunction
<JsonType
>
209 OCPP16IncomingRequestCommand
.CANCEL_RESERVATION
,
210 this.ajvIncomingRequest
.compile(
211 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
212 'assets/json-schemas/ocpp/1.6/CancelReservationResponse.json',
219 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
220 this.ajvIncomingRequest
.compile(
221 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ChangeAvailabilityResponse
>(
222 'assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
229 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
230 this.ajvIncomingRequest
.compile(
231 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeConfigurationResponse
>(
232 'assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
239 OCPP16IncomingRequestCommand
.CLEAR_CACHE
,
240 this.ajvIncomingRequest
.compile(
241 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
242 'assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
249 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
250 this.ajvIncomingRequest
.compile(
251 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ClearChargingProfileResponse
>(
252 'assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
259 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
260 this.ajvIncomingRequest
.compile(
261 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferResponse
>(
262 'assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
269 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
270 this.ajvIncomingRequest
.compile(
271 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16GetCompositeScheduleResponse
>(
272 'assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
279 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
280 this.ajvIncomingRequest
.compile(
281 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetConfigurationResponse
>(
282 'assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
289 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
290 this.ajvIncomingRequest
.compile(
291 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetDiagnosticsResponse
>(
292 'assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
299 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
300 this.ajvIncomingRequest
.compile(
301 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
302 'assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
309 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
310 this.ajvIncomingRequest
.compile(
311 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
312 'assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
319 OCPP16IncomingRequestCommand
.RESERVE_NOW
,
320 this.ajvIncomingRequest
.compile(
321 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ReserveNowResponse
>(
322 'assets/json-schemas/ocpp/1.6/ReserveNowResponse.json',
329 OCPP16IncomingRequestCommand
.RESET
,
330 this.ajvIncomingRequest
.compile(
331 OCPP16ServiceUtils
.parseJsonSchemaFile
<GenericResponse
>(
332 'assets/json-schemas/ocpp/1.6/ResetResponse.json',
339 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
340 this.ajvIncomingRequest
.compile(
341 OCPP16ServiceUtils
.parseJsonSchemaFile
<SetChargingProfileResponse
>(
342 'assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
349 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
350 this.ajvIncomingRequest
.compile(
351 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16TriggerMessageResponse
>(
352 'assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
359 OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
,
360 this.ajvIncomingRequest
.compile(
361 OCPP16ServiceUtils
.parseJsonSchemaFile
<UnlockConnectorResponse
>(
362 'assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
369 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
,
370 this.ajvIncomingRequest
.compile(
371 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16UpdateFirmwareResponse
>(
372 'assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
379 this.validatePayload
= this.validatePayload
.bind(this)
382 // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
383 public async responseHandler
<ReqType
extends JsonType
, ResType
extends JsonType
>(
384 chargingStation
: ChargingStation
,
385 commandName
: OCPP16RequestCommand
,
387 requestPayload
: ReqType
390 chargingStation
.inAcceptedState() ||
391 ((chargingStation
.inUnknownState() || chargingStation
.inPendingState()) &&
392 commandName
=== OCPP16RequestCommand
.BOOT_NOTIFICATION
) ||
393 (chargingStation
.stationInfo
?.ocppStrictCompliance
=== false &&
394 (chargingStation
.inUnknownState() || chargingStation
.inPendingState()))
397 this.responseHandlers
.has(commandName
) &&
398 OCPP16ServiceUtils
.isRequestCommandSupported(chargingStation
, commandName
)
401 this.validatePayload(chargingStation
, commandName
, payload
)
402 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
403 const responseHandler
= this.responseHandlers
.get(commandName
)!
404 if (isAsyncFunction(responseHandler
)) {
405 await responseHandler(chargingStation
, payload
, requestPayload
)
409 chargingStation
: ChargingStation
,
411 requestPayload
?: JsonType
413 )(chargingStation
, payload
, requestPayload
)
417 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
425 ErrorType
.NOT_IMPLEMENTED
,
426 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
437 ErrorType
.SECURITY_ERROR
,
438 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
442 )} while the charging station is not registered on the central server`,
449 private handleResponseAuthorize (
450 chargingStation
: ChargingStation
,
451 payload
: OCPP16AuthorizeResponse
,
452 requestPayload
: OCPP16AuthorizeRequest
454 let authorizeConnectorId
: number | undefined
455 if (chargingStation
.hasEvses
) {
456 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
458 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
459 if (connectorStatus
.authorizeIdTag
=== requestPayload
.idTag
) {
460 authorizeConnectorId
= connectorId
467 for (const connectorId
of chargingStation
.connectors
.keys()) {
470 chargingStation
.getConnectorStatus(connectorId
)?.authorizeIdTag
=== requestPayload
.idTag
472 authorizeConnectorId
= connectorId
477 if (authorizeConnectorId
!= null) {
478 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
479 const authorizeConnectorStatus
= chargingStation
.getConnectorStatus(authorizeConnectorId
)!
480 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
481 authorizeConnectorStatus
.idTagAuthorized
= true
483 `${chargingStation.logPrefix()} idTag '${
485 }' accepted on connector id ${authorizeConnectorId.toString()}`
488 authorizeConnectorStatus
.idTagAuthorized
= false
489 delete authorizeConnectorStatus
.authorizeIdTag
491 `${chargingStation.logPrefix()} idTag '${
493 }' rejected with status '${payload.idTagInfo.status}'`
498 `${chargingStation.logPrefix()} idTag '${
500 }' has no authorize request pending`
505 private handleResponseBootNotification (
506 chargingStation
: ChargingStation
,
507 payload
: OCPP16BootNotificationResponse
509 if (Object.values(RegistrationStatusEnumType
).includes(payload
.status)) {
510 chargingStation
.bootNotificationResponse
= payload
511 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
512 if (payload
.interval
!= null) {
515 OCPP16StandardParametersKey
.HeartbeatInterval
,
516 payload
.interval
.toString(),
518 { overwrite
: true, save
: true }
522 OCPP16StandardParametersKey
.HeartBeatInterval
,
523 payload
.interval
.toString(),
525 { overwrite
: true, save
: true }
528 if (chargingStation
.inAcceptedState()) {
529 chargingStation
.emit(ChargingStationEvents
.accepted
)
530 } else if (chargingStation
.inPendingState()) {
531 chargingStation
.emit(ChargingStationEvents
.pending
)
532 } else if (chargingStation
.inRejectedState()) {
533 chargingStation
.emit(ChargingStationEvents
.rejected
)
535 const logMsg
= `${chargingStation.logPrefix()} Charging station in '${
537 }' state on the central server`
538 payload
.status === RegistrationStatusEnumType
.REJECTED
539 ? logger
.warn(logMsg
)
540 : logger
.info(logMsg
)
542 delete chargingStation
.bootNotificationResponse
544 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
550 private async handleResponseStartTransaction (
551 chargingStation
: ChargingStation
,
552 payload
: OCPP16StartTransactionResponse
,
553 requestPayload
: OCPP16StartTransactionRequest
555 const { connectorId
} = requestPayload
556 if (connectorId
=== 0 || !chargingStation
.hasConnector(connectorId
)) {
558 `${chargingStation.logPrefix()} Trying to start a transaction on a non existing connector id ${connectorId.toString()}`
562 const connectorStatus
= chargingStation
.getConnectorStatus(connectorId
)
564 connectorStatus
?.transactionRemoteStarted
=== true &&
565 chargingStation
.getAuthorizeRemoteTxRequests() &&
566 chargingStation
.getLocalAuthListEnabled() &&
567 chargingStation
.hasIdTags() &&
568 connectorStatus
.idTagLocalAuthorized
=== false
571 `${chargingStation.logPrefix()} Trying to start a transaction with a not local authorized idTag ${
572 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
573 connectorStatus.localAuthorizeIdTag
574 } on connector id ${connectorId.toString()}`
576 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
580 connectorStatus
?.transactionRemoteStarted
=== true &&
581 chargingStation
.getAuthorizeRemoteTxRequests() &&
582 chargingStation
.stationInfo
?.remoteAuthorization
=== true &&
583 connectorStatus
.idTagLocalAuthorized
=== false &&
584 connectorStatus
.idTagAuthorized
=== false
587 `${chargingStation.logPrefix()} Trying to start a transaction with a not authorized idTag ${
588 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
589 connectorStatus.authorizeIdTag
590 } on connector id ${connectorId.toString()}`
592 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
596 connectorStatus
?.idTagAuthorized
=== true &&
597 connectorStatus
.authorizeIdTag
!= null &&
598 connectorStatus
.authorizeIdTag
!== requestPayload
.idTag
601 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
603 } different from the authorize request one ${
604 connectorStatus.authorizeIdTag
605 } on connector id ${connectorId.toString()}`
607 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
611 connectorStatus
?.idTagLocalAuthorized
=== true &&
612 connectorStatus
.localAuthorizeIdTag
!= null &&
613 connectorStatus
.localAuthorizeIdTag
!== requestPayload
.idTag
616 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
618 } different from the local authorized one ${
619 connectorStatus.localAuthorizeIdTag
620 } on connector id ${connectorId.toString()}`
622 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
625 if (connectorStatus
?.transactionStarted
=== true) {
627 `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector id ${connectorId.toString()} by idTag ${
628 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
629 connectorStatus.transactionIdTag
634 if (chargingStation
.hasEvses
) {
635 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
636 if (evseStatus
.connectors
.size
> 1) {
637 for (const [id
, status] of evseStatus
.connectors
) {
638 if (id
!== connectorId
&& status.transactionStarted
=== true) {
640 `${chargingStation.logPrefix()} Trying to start a transaction on an already used evse id ${evseId.toString()} by connector id ${id.toString()} with idTag ${
641 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
642 status.transactionIdTag
645 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
653 connectorStatus
?.status !== OCPP16ChargePointStatus
.Available
&&
654 connectorStatus
?.status !== OCPP16ChargePointStatus
.Preparing
657 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId.toString()} with status ${
658 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
659 connectorStatus?.status
664 if (!Number.isSafeInteger(payload
.transactionId
)) {
666 `${chargingStation.logPrefix()} Trying to start a transaction on connector id ${connectorId.toString()} with a non integer transaction id ${payload.transactionId.toString()}, converting to integer`
668 payload
.transactionId
= convertToInt(payload
.transactionId
)
671 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
672 connectorStatus
.transactionStarted
= true
673 connectorStatus
.transactionStart
= requestPayload
.timestamp
674 connectorStatus
.transactionId
= payload
.transactionId
675 connectorStatus
.transactionIdTag
= requestPayload
.idTag
676 connectorStatus
.transactionEnergyActiveImportRegisterValue
= 0
677 connectorStatus
.transactionBeginMeterValue
=
678 OCPP16ServiceUtils
.buildTransactionBeginMeterValue(
681 requestPayload
.meterStart
683 if (requestPayload
.reservationId
!= null) {
684 const reservation
= chargingStation
.getReservationBy(
686 requestPayload
.reservationId
688 if (reservation
!= null) {
689 if (reservation
.idTag
!== requestPayload
.idTag
) {
691 `${chargingStation.logPrefix()} Reserved transaction ${payload.transactionId.toString()} started with a different idTag ${
693 } than the reservation one ${reservation.idTag}`
696 if (hasReservationExpired(reservation
)) {
698 `${chargingStation.logPrefix()} Reserved transaction ${payload.transactionId.toString()} started with expired reservation ${requestPayload.reservationId.toString()} (expiry date: ${reservation.expiryDate.toISOString()}))`
701 await chargingStation
.removeReservation(
703 ReservationTerminationReason
.TRANSACTION_STARTED
707 `${chargingStation.logPrefix()} Reserved transaction ${payload.transactionId.toString()} started with unknown reservation ${requestPayload.reservationId.toString()}`
711 chargingStation
.stationInfo
?.beginEndMeterValues
=== true &&
712 (await chargingStation
.ocppRequestService
.requestHandler
<
713 OCPP16MeterValuesRequest
,
714 OCPP16MeterValuesResponse
715 >(chargingStation
, OCPP16RequestCommand
.METER_VALUES
, {
717 meterValue
: [connectorStatus
.transactionBeginMeterValue
],
718 transactionId
: payload
.transactionId
,
719 } satisfies OCPP16MeterValuesRequest
))
720 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
723 OCPP16ChargePointStatus
.Charging
726 `${chargingStation.logPrefix()} Transaction with id ${payload.transactionId.toString()} STARTED on ${
727 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
728 chargingStation.stationInfo?.chargingStationId
729 }#${connectorId.toString()} for idTag '${requestPayload.idTag}'`
731 if (chargingStation
.stationInfo
?.powerSharedByConnectors
=== true) {
732 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
733 ++chargingStation
.powerDivider
!
735 const configuredMeterValueSampleInterval
= getConfigurationKey(
737 OCPP16StandardParametersKey
.MeterValueSampleInterval
739 chargingStation
.startMeterValues(
741 configuredMeterValueSampleInterval
!= null
742 ? secondsToMilliseconds(convertToInt(configuredMeterValueSampleInterval
.value
))
743 : Constants
.DEFAULT_METER_VALUES_INTERVAL
747 `${chargingStation.logPrefix()} Starting transaction with id ${payload.transactionId.toString()} REJECTED on ${
748 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
749 chargingStation.stationInfo?.chargingStationId
750 }#${connectorId.toString()} with status '${payload.idTagInfo.status}', idTag '${
753 OCPP16ServiceUtils.hasReservation(chargingStation, connectorId, requestPayload.idTag)
754 ? // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
755 `, reservationId
'${requestPayload.reservationId?.toString()}'`
759 await this.resetConnectorOnStartTransactionError(chargingStation
, connectorId
)
763 private async handleResponseStopTransaction (
764 chargingStation
: ChargingStation
,
765 payload
: OCPP16StopTransactionResponse
,
766 requestPayload
: OCPP16StopTransactionRequest
768 const transactionConnectorId
= chargingStation
.getConnectorIdByTransactionId(
769 requestPayload
.transactionId
771 if (transactionConnectorId
== null) {
773 `${chargingStation.logPrefix()} Trying to stop a non existing transaction with id ${requestPayload.transactionId.toString()}`
777 chargingStation
.stationInfo
?.beginEndMeterValues
=== true &&
778 chargingStation
.stationInfo
.ocppStrictCompliance
=== false &&
779 chargingStation
.stationInfo
.outOfOrderEndMeterValues
=== true &&
780 (await chargingStation
.ocppRequestService
.requestHandler
<
781 OCPP16MeterValuesRequest
,
782 OCPP16MeterValuesResponse
783 >(chargingStation
, OCPP16RequestCommand
.METER_VALUES
, {
784 connectorId
: transactionConnectorId
,
786 OCPP16ServiceUtils
.buildTransactionEndMeterValue(
788 transactionConnectorId
,
789 requestPayload
.meterStop
792 transactionId
: requestPayload
.transactionId
,
795 !chargingStation
.isChargingStationAvailable() ||
796 !chargingStation
.isConnectorAvailable(transactionConnectorId
)
798 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
800 transactionConnectorId
,
801 OCPP16ChargePointStatus
.Unavailable
804 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
806 transactionConnectorId
,
807 OCPP16ChargePointStatus
.Available
810 if (chargingStation
.stationInfo
?.powerSharedByConnectors
=== true) {
811 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
812 chargingStation
.powerDivider
!--
814 resetConnectorStatus(chargingStation
.getConnectorStatus(transactionConnectorId
))
815 chargingStation
.stopMeterValues(transactionConnectorId
)
816 const logMsg
= `${chargingStation.logPrefix()} Transaction with id ${requestPayload.transactionId.toString()} STOPPED on ${
817 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
818 chargingStation.stationInfo?.chargingStationId
819 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
820 }#${transactionConnectorId.toString()} with status '${payload.idTagInfo?.status}'`
822 payload
.idTagInfo
== null ||
823 payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
831 private async resetConnectorOnStartTransactionError (
832 chargingStation
: ChargingStation
,
835 chargingStation
.stopMeterValues(connectorId
)
836 const connectorStatus
= chargingStation
.getConnectorStatus(connectorId
)
837 resetConnectorStatus(connectorStatus
)
838 await OCPP16ServiceUtils
.restoreConnectorStatus(chargingStation
, connectorId
, connectorStatus
)
841 private validatePayload (
842 chargingStation
: ChargingStation
,
843 commandName
: OCPP16RequestCommand
,
846 if (this.payloadValidateFunctions
.has(commandName
)) {
847 return this.validateResponsePayload(chargingStation
, commandName
, payload
)
850 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema validation function found for command '${commandName}' PDU validation`