1 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
3 import { AuthorizeRequest
, OCPP16AuthorizationStatus
, OCPP16AuthorizeResponse
, OCPP16StartTransactionResponse
, OCPP16StopTransactionResponse
, StartTransactionRequest
, StopTransactionRequest
} from
'../../../types/ocpp/1.6/Transaction';
4 import { HeartbeatRequest
, OCPP16BootNotificationRequest
, OCPP16RequestCommand
, StatusNotificationRequest
} from
'../../../types/ocpp/1.6/Requests';
5 import { HeartbeatResponse
, OCPP16BootNotificationResponse
, OCPP16RegistrationStatus
, StatusNotificationResponse
} from
'../../../types/ocpp/1.6/Responses';
6 import { MeterValuesRequest
, MeterValuesResponse
} from
'../../../types/ocpp/1.6/MeterValues';
8 import { OCPP16ChargePointStatus
} from
'../../../types/ocpp/1.6/ChargePointStatus';
9 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils';
10 import { OCPP16StandardParametersKey
} from
'../../../types/ocpp/1.6/Configuration';
11 import OCPPResponseService from
'../OCPPResponseService';
12 import Utils from
'../../../utils/Utils';
13 import logger from
'../../../utils/Logger';
15 export default class OCPP16ResponseService
extends OCPPResponseService
{
16 public async handleResponse(commandName
: OCPP16RequestCommand
, payload
: Record
<string, unknown
> | string, requestPayload
: Record
<string, unknown
>): Promise
<void> {
17 const responseCallbackMethodName
= `handleResponse${commandName}`;
18 if (typeof this[responseCallbackMethodName
] === 'function') {
19 await this[responseCallbackMethodName
](payload
, requestPayload
);
21 logger
.error(this.chargingStation
.logPrefix() + ' Trying to call an undefined response callback method: ' + responseCallbackMethodName
);
25 private handleResponseBootNotification(payload
: OCPP16BootNotificationResponse
, requestPayload
: OCPP16BootNotificationRequest
): void {
26 if (payload
.status === OCPP16RegistrationStatus
.ACCEPTED
) {
27 this.chargingStation
.addConfigurationKey(OCPP16StandardParametersKey
.HeartBeatInterval
, payload
.interval
.toString());
28 this.chargingStation
.addConfigurationKey(OCPP16StandardParametersKey
.HeartbeatInterval
, payload
.interval
.toString(), false, false);
29 this.chargingStation
.heartbeatSetInterval
? this.chargingStation
.restartHeartbeat() : this.chargingStation
.startHeartbeat();
30 } else if (payload
.status === OCPP16RegistrationStatus
.PENDING
) {
31 logger
.info(this.chargingStation
.logPrefix() + ' Charging station in pending state on the central server');
33 logger
.warn(this.chargingStation
.logPrefix() + ' Charging station rejected by the central server');
37 private async handleResponseStartTransaction(payload
: OCPP16StartTransactionResponse
, requestPayload
: StartTransactionRequest
): Promise
<void> {
38 const connectorId
= requestPayload
.connectorId
;
40 let transactionConnectorId
: number;
41 for (const connector
in this.chargingStation
.connectors
) {
42 if (Utils
.convertToInt(connector
) > 0 && Utils
.convertToInt(connector
) === connectorId
) {
43 transactionConnectorId
= Utils
.convertToInt(connector
);
47 if (!transactionConnectorId
) {
48 logger
.error(this.chargingStation
.logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId
.toString());
51 if (this.chargingStation
.getConnector(connectorId
).authorized
&& this.chargingStation
.getConnector(connectorId
).authorizeIdTag
!== requestPayload
.idTag
) {
52 logger
.error(this.chargingStation
.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload
.idTag
+ ' different from the authorize request one ' + this.chargingStation
.getConnector(connectorId
).authorizeIdTag
+ ' on connector Id ' + connectorId
.toString());
55 if (this.chargingStation
.getConnector(connectorId
)?.transactionStarted
) {
56 logger
.debug(this.chargingStation
.logPrefix() + ' Trying to start a transaction on an already used connector ' + connectorId
.toString() + ': %j', this.chargingStation
.getConnector(connectorId
));
59 if (this.chargingStation
.getConnector(connectorId
)?.status !== OCPP16ChargePointStatus
.AVAILABLE
60 && this.chargingStation
.getConnector(connectorId
)?.status !== OCPP16ChargePointStatus
.PREPARING
) {
61 logger
.error(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${this.chargingStation.getConnector(connectorId)?.status}`);
64 if (!Number.isInteger(payload
.transactionId
)) {
65 logger
.warn(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${payload.transactionId}, converting to integer`);
66 payload
.transactionId
= Utils
.convertToInt(payload
.transactionId
);
69 if (payload
.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
70 this.chargingStation
.getConnector(connectorId
).transactionStarted
= true;
71 this.chargingStation
.getConnector(connectorId
).transactionId
= payload
.transactionId
;
72 this.chargingStation
.getConnector(connectorId
).transactionIdTag
= requestPayload
.idTag
;
73 this.chargingStation
.getConnector(connectorId
).transactionEnergyActiveImportRegisterValue
= 0;
74 this.chargingStation
.getConnector(connectorId
).transactionBeginMeterValue
= OCPP16ServiceUtils
.buildTransactionBeginMeterValue(this.chargingStation
, connectorId
,
75 requestPayload
.meterStart
);
76 this.chargingStation
.getBeginEndMeterValues() && await this.chargingStation
.ocppRequestService
.sendTransactionBeginMeterValues(connectorId
, payload
.transactionId
,
77 this.chargingStation
.getConnector(connectorId
).transactionBeginMeterValue
);
78 await this.chargingStation
.ocppRequestService
.sendStatusNotification(connectorId
, OCPP16ChargePointStatus
.CHARGING
);
79 this.chargingStation
.getConnector(connectorId
).status = OCPP16ChargePointStatus
.CHARGING
;
80 logger
.info(this.chargingStation
.logPrefix() + ' Transaction ' + payload
.transactionId
.toString() + ' STARTED on ' + this.chargingStation
.stationInfo
.chargingStationId
+ '#' + connectorId
.toString() + ' for idTag ' + requestPayload
.idTag
);
81 if (this.chargingStation
.stationInfo
.powerSharedByConnectors
) {
82 this.chargingStation
.stationInfo
.powerDivider
++;
84 const configuredMeterValueSampleInterval
= this.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValueSampleInterval
);
85 this.chargingStation
.startMeterValues(connectorId
, configuredMeterValueSampleInterval
? Utils
.convertToInt(configuredMeterValueSampleInterval
.value
) * 1000 : 60000);
87 logger
.warn(this.chargingStation
.logPrefix() + ' Starting transaction id ' + payload
.transactionId
.toString() + ' REJECTED with status ' + payload
?.idTagInfo
?.status + ', idTag ' + requestPayload
.idTag
);
88 this.chargingStation
.resetTransactionOnConnector(connectorId
);
89 if (this.chargingStation
.getConnector(connectorId
).status !== OCPP16ChargePointStatus
.AVAILABLE
) {
90 await this.chargingStation
.ocppRequestService
.sendStatusNotification(connectorId
, OCPP16ChargePointStatus
.AVAILABLE
);
91 this.chargingStation
.getConnector(connectorId
).status = OCPP16ChargePointStatus
.AVAILABLE
;
96 private async handleResponseStopTransaction(payload
: OCPP16StopTransactionResponse
, requestPayload
: StopTransactionRequest
): Promise
<void> {
97 let transactionConnectorId
: number;
98 for (const connector
in this.chargingStation
.connectors
) {
99 if (Utils
.convertToInt(connector
) > 0 && this.chargingStation
.getConnector(Utils
.convertToInt(connector
))?.transactionId
=== requestPayload
.transactionId
) {
100 transactionConnectorId
= Utils
.convertToInt(connector
);
104 if (!transactionConnectorId
) {
105 logger
.error(this.chargingStation
.logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload
.transactionId
.toString());
108 if (payload
.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
109 (this.chargingStation
.getBeginEndMeterValues() && this.chargingStation
.getOutOfOrderEndMeterValues())
110 && await this.chargingStation
.ocppRequestService
.sendTransactionEndMeterValues(transactionConnectorId
, requestPayload
.transactionId
,
111 OCPP16ServiceUtils
.buildTransactionEndMeterValue(this.chargingStation
, transactionConnectorId
, requestPayload
.meterStop
));
112 if (!this.chargingStation
.isChargingStationAvailable() || !this.chargingStation
.isConnectorAvailable(transactionConnectorId
)) {
113 await this.chargingStation
.ocppRequestService
.sendStatusNotification(transactionConnectorId
, OCPP16ChargePointStatus
.UNAVAILABLE
);
114 this.chargingStation
.getConnector(transactionConnectorId
).status = OCPP16ChargePointStatus
.UNAVAILABLE
;
116 await this.chargingStation
.ocppRequestService
.sendStatusNotification(transactionConnectorId
, OCPP16ChargePointStatus
.AVAILABLE
);
117 this.chargingStation
.getConnector(transactionConnectorId
).status = OCPP16ChargePointStatus
.AVAILABLE
;
119 if (this.chargingStation
.stationInfo
.powerSharedByConnectors
) {
120 this.chargingStation
.stationInfo
.powerDivider
--;
122 logger
.info(this.chargingStation
.logPrefix() + ' Transaction ' + requestPayload
.transactionId
.toString() + ' STOPPED on ' + this.chargingStation
.stationInfo
.chargingStationId
+ '#' + transactionConnectorId
.toString());
123 this.chargingStation
.resetTransactionOnConnector(transactionConnectorId
);
125 logger
.warn(this.chargingStation
.logPrefix() + ' Stopping transaction id ' + requestPayload
.transactionId
.toString() + ' REJECTED with status ' + payload
.idTagInfo
?.status);
129 private handleResponseStatusNotification(payload
: StatusNotificationRequest
, requestPayload
: StatusNotificationResponse
): void {
130 logger
.debug(this.chargingStation
.logPrefix() + ' Status notification response received: %j to StatusNotification request: %j', payload
, requestPayload
);
133 private handleResponseMeterValues(payload
: MeterValuesRequest
, requestPayload
: MeterValuesResponse
): void {
134 logger
.debug(this.chargingStation
.logPrefix() + ' MeterValues response received: %j to MeterValues request: %j', payload
, requestPayload
);
137 private handleResponseHeartbeat(payload
: HeartbeatResponse
, requestPayload
: HeartbeatRequest
): void {
138 logger
.debug(this.chargingStation
.logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload
, requestPayload
);
141 private handleResponseAuthorize(payload
: OCPP16AuthorizeResponse
, requestPayload
: AuthorizeRequest
): void {
142 let authorizeConnectorId
: number;
143 for (const connector
in this.chargingStation
.connectors
) {
144 if (Utils
.convertToInt(connector
) > 0 && this.chargingStation
.getConnector(Utils
.convertToInt(connector
))?.authorizeIdTag
=== requestPayload
.idTag
) {
145 authorizeConnectorId
= Utils
.convertToInt(connector
);
149 if (payload
.idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
150 this.chargingStation
.getConnector(authorizeConnectorId
).authorized
= true;
151 logger
.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`);
153 this.chargingStation
.getConnector(authorizeConnectorId
).authorized
= false;
154 delete this.chargingStation
.getConnector(authorizeConnectorId
).authorizeIdTag
;
155 logger
.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`);