Validate response PDU (#137)
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ResponseService.ts
CommitLineData
c8eeb62b
JB
1// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
2
844e496b
JB
3import fs from 'fs';
4import path from 'path';
5import { fileURLToPath } from 'url';
6
7import { JSONSchemaType } from 'ajv';
8
8114d10e
JB
9import OCPPError from '../../../exception/OCPPError';
10import { JsonType } from '../../../types/JsonType';
11import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointErrorCode';
12import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
13import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration';
e7aeea18 14import {
8114d10e
JB
15 OCPP16MeterValuesRequest,
16 OCPP16MeterValuesResponse,
17} from '../../../types/ocpp/1.6/MeterValues';
e7aeea18 18import {
ef6fa3fb 19 OCPP16BootNotificationRequest,
e7aeea18 20 OCPP16RequestCommand,
ef6fa3fb 21 OCPP16StatusNotificationRequest,
e7aeea18
JB
22} from '../../../types/ocpp/1.6/Requests';
23import {
e7aeea18 24 OCPP16BootNotificationResponse,
844e496b 25 OCPP16HeartbeatResponse,
e7aeea18 26 OCPP16RegistrationStatus,
f22266fd 27 OCPP16StatusNotificationResponse,
e7aeea18 28} from '../../../types/ocpp/1.6/Responses';
ef6fa3fb 29import {
8114d10e
JB
30 OCPP16AuthorizationStatus,
31 OCPP16AuthorizeRequest,
32 OCPP16AuthorizeResponse,
33 OCPP16StartTransactionRequest,
34 OCPP16StartTransactionResponse,
35 OCPP16StopTransactionRequest,
36 OCPP16StopTransactionResponse,
37} from '../../../types/ocpp/1.6/Transaction';
a4bc2942 38import { ErrorType } from '../../../types/ocpp/ErrorType';
74c6a954 39import { ResponseHandler } from '../../../types/ocpp/Responses';
9f2e3130 40import logger from '../../../utils/Logger';
8114d10e
JB
41import Utils from '../../../utils/Utils';
42import type ChargingStation from '../../ChargingStation';
43import { ChargingStationConfigurationUtils } from '../../ChargingStationConfigurationUtils';
65554cc3 44import { ChargingStationUtils } from '../../ChargingStationUtils';
8114d10e
JB
45import OCPPResponseService from '../OCPPResponseService';
46import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
c0560973 47
909dcf2d
JB
48const moduleName = 'OCPP16ResponseService';
49
c0560973 50export default class OCPP16ResponseService extends OCPPResponseService {
58144adb 51 private responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>;
844e496b
JB
52 private bootNotificationResponseJsonSchema: JSONSchemaType<OCPP16BootNotificationResponse>;
53 private heartbeatResponseJsonSchema: JSONSchemaType<OCPP16HeartbeatResponse>;
54 private authorizeResponseJsonSchema: JSONSchemaType<OCPP16AuthorizeResponse>;
55 private startTransactionResponseJsonSchema: JSONSchemaType<OCPP16StartTransactionResponse>;
56 private stopTransactionResponseJsonSchema: JSONSchemaType<OCPP16StopTransactionResponse>;
57 private statusNotificationResponseJsonSchema: JSONSchemaType<OCPP16StatusNotificationResponse>;
58 private meterValuesResponseJsonSchema: JSONSchemaType<OCPP16MeterValuesResponse>;
58144adb 59
08f130a0 60 public constructor() {
909dcf2d 61 if (new.target?.name === moduleName) {
06127450 62 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
9f2e3130 63 }
08f130a0 64 super();
58144adb
JB
65 this.responseHandlers = new Map<OCPP16RequestCommand, ResponseHandler>([
66 [OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)],
67 [OCPP16RequestCommand.HEARTBEAT, this.handleResponseHeartbeat.bind(this)],
68 [OCPP16RequestCommand.AUTHORIZE, this.handleResponseAuthorize.bind(this)],
69 [OCPP16RequestCommand.START_TRANSACTION, this.handleResponseStartTransaction.bind(this)],
70 [OCPP16RequestCommand.STOP_TRANSACTION, this.handleResponseStopTransaction.bind(this)],
71 [OCPP16RequestCommand.STATUS_NOTIFICATION, this.handleResponseStatusNotification.bind(this)],
e7aeea18 72 [OCPP16RequestCommand.METER_VALUES, this.handleResponseMeterValues.bind(this)],
58144adb 73 ]);
844e496b
JB
74 this.bootNotificationResponseJsonSchema = JSON.parse(
75 fs.readFileSync(
76 path.resolve(
77 path.dirname(fileURLToPath(import.meta.url)),
78 '../../../assets/json-schemas/ocpp/1.6/BootNotificationResponse.json'
79 ),
80 'utf8'
81 )
82 ) as JSONSchemaType<OCPP16BootNotificationResponse>;
83 this.heartbeatResponseJsonSchema = JSON.parse(
84 fs.readFileSync(
85 path.resolve(
86 path.dirname(fileURLToPath(import.meta.url)),
87 '../../../assets/json-schemas/ocpp/1.6/HeartbeatResponse.json'
88 ),
89 'utf8'
90 )
91 ) as JSONSchemaType<OCPP16HeartbeatResponse>;
92 this.authorizeResponseJsonSchema = JSON.parse(
93 fs.readFileSync(
94 path.resolve(
95 path.dirname(fileURLToPath(import.meta.url)),
96 '../../../assets/json-schemas/ocpp/1.6/AuthorizeResponse.json'
97 ),
98 'utf8'
99 )
100 ) as JSONSchemaType<OCPP16AuthorizeResponse>;
101 this.startTransactionResponseJsonSchema = JSON.parse(
102 fs.readFileSync(
103 path.resolve(
104 path.dirname(fileURLToPath(import.meta.url)),
105 '../../../assets/json-schemas/ocpp/1.6/StartTransactionResponse.json'
106 ),
107 'utf8'
108 )
109 ) as JSONSchemaType<OCPP16StartTransactionResponse>;
110 this.stopTransactionResponseJsonSchema = JSON.parse(
111 fs.readFileSync(
112 path.resolve(
113 path.dirname(fileURLToPath(import.meta.url)),
114 '../../../assets/json-schemas/ocpp/1.6/StopTransactionResponse.json'
115 ),
116 'utf8'
117 )
118 ) as JSONSchemaType<OCPP16StopTransactionResponse>;
119 this.statusNotificationResponseJsonSchema = JSON.parse(
120 fs.readFileSync(
121 path.resolve(
122 path.dirname(fileURLToPath(import.meta.url)),
123 '../../../assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json'
124 ),
125 'utf8'
126 )
127 ) as JSONSchemaType<OCPP16StatusNotificationResponse>;
128 this.meterValuesResponseJsonSchema = JSON.parse(
129 fs.readFileSync(
130 path.resolve(
131 path.dirname(fileURLToPath(import.meta.url)),
132 '../../../assets/json-schemas/ocpp/1.6/MeterValuesResponse.json'
133 ),
134 'utf8'
135 )
136 ) as JSONSchemaType<OCPP16MeterValuesResponse>;
58144adb
JB
137 }
138
f7f98c68 139 public async responseHandler(
08f130a0 140 chargingStation: ChargingStation,
e7aeea18 141 commandName: OCPP16RequestCommand,
5cc4b63b
JB
142 payload: JsonType,
143 requestPayload: JsonType
e7aeea18 144 ): Promise<void> {
08f130a0 145 if (chargingStation.isRegistered() || commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) {
65554cc3
JB
146 if (
147 this.responseHandlers.has(commandName) &&
ada189a8 148 ChargingStationUtils.isRequestCommandSupported(commandName, chargingStation)
65554cc3 149 ) {
124f3553 150 try {
08f130a0 151 await this.responseHandlers.get(commandName)(chargingStation, payload, requestPayload);
124f3553 152 } catch (error) {
08f130a0 153 logger.error(chargingStation.logPrefix() + ' Handle request response error: %j', error);
124f3553
JB
154 throw error;
155 }
156 } else {
157 // Throw exception
e7aeea18
JB
158 throw new OCPPError(
159 ErrorType.NOT_IMPLEMENTED,
e3018bc4 160 `${commandName} is not implemented to handle request response PDU ${JSON.stringify(
e7aeea18
JB
161 payload,
162 null,
163 2
164 )}`,
7369e417
JB
165 commandName,
166 payload
e7aeea18 167 );
887fef76 168 }
c0560973 169 } else {
e7aeea18
JB
170 throw new OCPPError(
171 ErrorType.SECURITY_ERROR,
e3018bc4 172 `${commandName} cannot be issued to handle request response PDU ${JSON.stringify(
e7aeea18
JB
173 payload,
174 null,
175 2
176 )} while the charging station is not registered on the central server. `,
7369e417
JB
177 commandName,
178 payload
e7aeea18 179 );
c0560973
JB
180 }
181 }
182
08f130a0
JB
183 private handleResponseBootNotification(
184 chargingStation: ChargingStation,
185 payload: OCPP16BootNotificationResponse
186 ): void {
844e496b
JB
187 this.validateResponsePayload(
188 chargingStation,
189 OCPP16RequestCommand.BOOT_NOTIFICATION,
190 this.bootNotificationResponseJsonSchema,
191 payload
192 );
c0560973 193 if (payload.status === OCPP16RegistrationStatus.ACCEPTED) {
17ac262c
JB
194 ChargingStationConfigurationUtils.addConfigurationKey(
195 chargingStation,
f0f65a62 196 OCPP16StandardParametersKey.HeartbeatInterval,
a95873d8
JB
197 payload.interval.toString(),
198 {},
199 { overwrite: true, save: true }
e7aeea18 200 );
17ac262c
JB
201 ChargingStationConfigurationUtils.addConfigurationKey(
202 chargingStation,
f0f65a62 203 OCPP16StandardParametersKey.HeartBeatInterval,
e7aeea18 204 payload.interval.toString(),
00db15b8 205 { visible: false },
a95873d8 206 { overwrite: true, save: true }
e7aeea18 207 );
08f130a0
JB
208 chargingStation.heartbeatSetInterval
209 ? chargingStation.restartHeartbeat()
210 : chargingStation.startHeartbeat();
672fed6e 211 }
74c6a954 212 if (Object.values(OCPP16RegistrationStatus).includes(payload.status)) {
08f130a0 213 const logMsg = `${chargingStation.logPrefix()} Charging station in '${
e7aeea18
JB
214 payload.status
215 }' state on the central server`;
216 payload.status === OCPP16RegistrationStatus.REJECTED
217 ? logger.warn(logMsg)
218 : logger.info(logMsg);
c0560973 219 } else {
e7aeea18 220 logger.error(
08f130a0 221 chargingStation.logPrefix() +
e7aeea18
JB
222 ' Charging station boot notification response received: %j with undefined registration status',
223 payload
224 );
c0560973
JB
225 }
226 }
227
844e496b
JB
228 private handleResponseHeartbeat(
229 chargingStation: ChargingStation,
230 payload: OCPP16HeartbeatResponse
231 ): void {
232 this.validateResponsePayload(
233 chargingStation,
234 OCPP16RequestCommand.HEARTBEAT,
235 this.heartbeatResponseJsonSchema,
236 payload
237 );
238 }
58144adb 239
e7aeea18 240 private handleResponseAuthorize(
08f130a0 241 chargingStation: ChargingStation,
e7aeea18 242 payload: OCPP16AuthorizeResponse,
ef6fa3fb 243 requestPayload: OCPP16AuthorizeRequest
e7aeea18 244 ): void {
844e496b
JB
245 this.validateResponsePayload(
246 chargingStation,
247 OCPP16RequestCommand.AUTHORIZE,
248 this.authorizeResponseJsonSchema,
249 payload
250 );
58144adb 251 let authorizeConnectorId: number;
08f130a0 252 for (const connectorId of chargingStation.connectors.keys()) {
e7aeea18
JB
253 if (
254 connectorId > 0 &&
08f130a0 255 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag
e7aeea18 256 ) {
734d790d 257 authorizeConnectorId = connectorId;
58144adb
JB
258 break;
259 }
260 }
261 if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
08f130a0 262 chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true;
e7aeea18 263 logger.debug(
08f130a0 264 `${chargingStation.logPrefix()} IdTag ${
e7aeea18
JB
265 requestPayload.idTag
266 } authorized on connector ${authorizeConnectorId}`
267 );
58144adb 268 } else {
08f130a0
JB
269 chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false;
270 delete chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag;
e7aeea18 271 logger.debug(
08f130a0 272 `${chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status '${
e7aeea18 273 payload.idTagInfo.status
e8e865ea 274 }' on connector ${authorizeConnectorId}`
e7aeea18 275 );
58144adb
JB
276 }
277 }
278
e7aeea18 279 private async handleResponseStartTransaction(
08f130a0 280 chargingStation: ChargingStation,
e7aeea18 281 payload: OCPP16StartTransactionResponse,
ef6fa3fb 282 requestPayload: OCPP16StartTransactionRequest
e7aeea18 283 ): Promise<void> {
844e496b
JB
284 this.validateResponsePayload(
285 chargingStation,
286 OCPP16RequestCommand.START_TRANSACTION,
287 this.startTransactionResponseJsonSchema,
288 payload
289 );
c0560973
JB
290 const connectorId = requestPayload.connectorId;
291
292 let transactionConnectorId: number;
08f130a0 293 for (const id of chargingStation.connectors.keys()) {
734d790d
JB
294 if (id > 0 && id === connectorId) {
295 transactionConnectorId = id;
c0560973
JB
296 break;
297 }
298 }
299 if (!transactionConnectorId) {
e7aeea18 300 logger.error(
08f130a0 301 chargingStation.logPrefix() +
e7aeea18
JB
302 ' Trying to start a transaction on a non existing connector Id ' +
303 connectorId.toString()
304 );
c0560973
JB
305 return;
306 }
e7aeea18 307 if (
08f130a0
JB
308 chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted &&
309 chargingStation.getAuthorizeRemoteTxRequests() &&
310 chargingStation.getLocalAuthListEnabled() &&
311 chargingStation.hasAuthorizedTags() &&
312 !chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
e7aeea18
JB
313 ) {
314 logger.error(
08f130a0 315 chargingStation.logPrefix() +
e7aeea18 316 ' Trying to start a transaction with a not local authorized idTag ' +
08f130a0 317 chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag +
e7aeea18
JB
318 ' on connector Id ' +
319 connectorId.toString()
320 );
08f130a0 321 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
322 return;
323 }
e7aeea18 324 if (
08f130a0
JB
325 chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted &&
326 chargingStation.getAuthorizeRemoteTxRequests() &&
327 chargingStation.getMayAuthorizeAtRemoteStart() &&
328 !chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized &&
329 !chargingStation.getConnectorStatus(connectorId).idTagAuthorized
e7aeea18
JB
330 ) {
331 logger.error(
08f130a0 332 chargingStation.logPrefix() +
e7aeea18 333 ' Trying to start a transaction with a not authorized idTag ' +
08f130a0 334 chargingStation.getConnectorStatus(connectorId).authorizeIdTag +
e7aeea18
JB
335 ' on connector Id ' +
336 connectorId.toString()
337 );
08f130a0 338 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
339 return;
340 }
e7aeea18 341 if (
08f130a0
JB
342 chargingStation.getConnectorStatus(connectorId).idTagAuthorized &&
343 chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag
e7aeea18
JB
344 ) {
345 logger.error(
08f130a0 346 chargingStation.logPrefix() +
e7aeea18
JB
347 ' Trying to start a transaction with an idTag ' +
348 requestPayload.idTag +
349 ' different from the authorize request one ' +
08f130a0 350 chargingStation.getConnectorStatus(connectorId).authorizeIdTag +
e7aeea18
JB
351 ' on connector Id ' +
352 connectorId.toString()
353 );
08f130a0 354 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
355 return;
356 }
e7aeea18 357 if (
08f130a0
JB
358 chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized &&
359 chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !== requestPayload.idTag
e7aeea18
JB
360 ) {
361 logger.error(
08f130a0 362 chargingStation.logPrefix() +
e7aeea18
JB
363 ' Trying to start a transaction with an idTag ' +
364 requestPayload.idTag +
365 ' different from the local authorized one ' +
08f130a0 366 chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag +
e7aeea18
JB
367 ' on connector Id ' +
368 connectorId.toString()
369 );
08f130a0 370 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
163547b1
JB
371 return;
372 }
08f130a0 373 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
e7aeea18 374 logger.debug(
08f130a0 375 chargingStation.logPrefix() +
e7aeea18
JB
376 ' Trying to start a transaction on an already used connector ' +
377 connectorId.toString() +
378 ': %j',
08f130a0 379 chargingStation.getConnectorStatus(connectorId)
e7aeea18 380 );
c0560973
JB
381 return;
382 }
e7aeea18 383 if (
08f130a0 384 chargingStation.getConnectorStatus(connectorId)?.status !==
e7aeea18 385 OCPP16ChargePointStatus.AVAILABLE &&
08f130a0 386 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.PREPARING
e7aeea18
JB
387 ) {
388 logger.error(
08f130a0
JB
389 `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${
390 chargingStation.getConnectorStatus(connectorId)?.status
e7aeea18
JB
391 }`
392 );
290d006c
JB
393 return;
394 }
f3a6f63b 395 if (!Number.isInteger(payload.transactionId)) {
e7aeea18 396 logger.warn(
08f130a0 397 `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${
e7aeea18
JB
398 payload.transactionId
399 }, converting to integer`
400 );
f3a6f63b
JB
401 payload.transactionId = Utils.convertToInt(payload.transactionId);
402 }
c0560973 403
f0c6ed89 404 if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
08f130a0
JB
405 chargingStation.getConnectorStatus(connectorId).transactionStarted = true;
406 chargingStation.getConnectorStatus(connectorId).transactionId = payload.transactionId;
407 chargingStation.getConnectorStatus(connectorId).transactionIdTag = requestPayload.idTag;
408 chargingStation.getConnectorStatus(
e7aeea18
JB
409 connectorId
410 ).transactionEnergyActiveImportRegisterValue = 0;
08f130a0 411 chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue =
e7aeea18 412 OCPP16ServiceUtils.buildTransactionBeginMeterValue(
08f130a0 413 chargingStation,
e7aeea18
JB
414 connectorId,
415 requestPayload.meterStart
416 );
08f130a0
JB
417 chargingStation.getBeginEndMeterValues() &&
418 (await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
419 OCPP16MeterValuesRequest,
420 OCPP16MeterValuesResponse
08f130a0 421 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
93b4a429 422 connectorId,
ef6fa3fb 423 transactionId: payload.transactionId,
7369e417 424 meterValue: [chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue],
ef6fa3fb 425 }));
08f130a0 426 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
427 OCPP16StatusNotificationRequest,
428 OCPP16StatusNotificationResponse
08f130a0 429 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb
JB
430 connectorId,
431 status: OCPP16ChargePointStatus.CHARGING,
432 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
433 });
08f130a0 434 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.CHARGING;
e7aeea18 435 logger.info(
08f130a0 436 chargingStation.logPrefix() +
e7aeea18
JB
437 ' Transaction ' +
438 payload.transactionId.toString() +
439 ' STARTED on ' +
08f130a0 440 chargingStation.stationInfo.chargingStationId +
e7aeea18
JB
441 '#' +
442 connectorId.toString() +
443 ' for idTag ' +
444 requestPayload.idTag
445 );
08f130a0 446 if (chargingStation.stationInfo.powerSharedByConnectors) {
fa7bccf4 447 chargingStation.powerDivider++;
c0560973 448 }
17ac262c
JB
449 const configuredMeterValueSampleInterval =
450 ChargingStationConfigurationUtils.getConfigurationKey(
451 chargingStation,
452 OCPP16StandardParametersKey.MeterValueSampleInterval
453 );
08f130a0 454 chargingStation.startMeterValues(
e7aeea18
JB
455 connectorId,
456 configuredMeterValueSampleInterval
457 ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000
458 : 60000
459 );
c0560973 460 } else {
e7aeea18 461 logger.warn(
08f130a0 462 chargingStation.logPrefix() +
e7aeea18
JB
463 ' Starting transaction id ' +
464 payload.transactionId.toString() +
e8e865ea 465 " REJECTED with status '" +
e7aeea18 466 payload?.idTagInfo?.status +
e8e865ea 467 "', idTag " +
e7aeea18
JB
468 requestPayload.idTag
469 );
08f130a0 470 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
471 }
472 }
473
08f130a0
JB
474 private async resetConnectorOnStartTransactionError(
475 chargingStation: ChargingStation,
476 connectorId: number
477 ): Promise<void> {
478 chargingStation.resetConnectorStatus(connectorId);
e7aeea18 479 if (
08f130a0 480 chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE
e7aeea18 481 ) {
08f130a0 482 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
483 OCPP16StatusNotificationRequest,
484 OCPP16StatusNotificationResponse
08f130a0 485 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb
JB
486 connectorId,
487 status: OCPP16ChargePointStatus.AVAILABLE,
488 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
489 });
08f130a0 490 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
c0560973
JB
491 }
492 }
493
e7aeea18 494 private async handleResponseStopTransaction(
08f130a0 495 chargingStation: ChargingStation,
e7aeea18 496 payload: OCPP16StopTransactionResponse,
ef6fa3fb 497 requestPayload: OCPP16StopTransactionRequest
e7aeea18 498 ): Promise<void> {
844e496b
JB
499 this.validateResponsePayload(
500 chargingStation,
501 OCPP16RequestCommand.STOP_TRANSACTION,
502 this.stopTransactionResponseJsonSchema,
503 payload
504 );
08f130a0 505 const transactionConnectorId = chargingStation.getConnectorIdByTransactionId(
f479a792
JB
506 requestPayload.transactionId
507 );
c0560973 508 if (!transactionConnectorId) {
e7aeea18 509 logger.error(
08f130a0 510 chargingStation.logPrefix() +
e7aeea18
JB
511 ' Trying to stop a non existing transaction ' +
512 requestPayload.transactionId.toString()
513 );
c0560973
JB
514 return;
515 }
516 if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
08f130a0
JB
517 chargingStation.getBeginEndMeterValues() &&
518 !chargingStation.getOcppStrictCompliance() &&
519 chargingStation.getOutOfOrderEndMeterValues() &&
520 (await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
521 OCPP16MeterValuesRequest,
522 OCPP16MeterValuesResponse
08f130a0 523 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
ef6fa3fb
JB
524 connectorId: transactionConnectorId,
525 transactionId: requestPayload.transactionId,
7369e417
JB
526 meterValue: [
527 OCPP16ServiceUtils.buildTransactionEndMeterValue(
528 chargingStation,
529 transactionConnectorId,
530 requestPayload.meterStop
531 ),
532 ],
ef6fa3fb 533 }));
e7aeea18 534 if (
08f130a0
JB
535 !chargingStation.isChargingStationAvailable() ||
536 !chargingStation.isConnectorAvailable(transactionConnectorId)
e7aeea18 537 ) {
08f130a0 538 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
539 OCPP16StatusNotificationRequest,
540 OCPP16StatusNotificationResponse
08f130a0 541 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb
JB
542 connectorId: transactionConnectorId,
543 status: OCPP16ChargePointStatus.UNAVAILABLE,
544 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
545 });
08f130a0 546 chargingStation.getConnectorStatus(transactionConnectorId).status =
e7aeea18 547 OCPP16ChargePointStatus.UNAVAILABLE;
c0560973 548 } else {
08f130a0 549 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
550 OCPP16BootNotificationRequest,
551 OCPP16BootNotificationResponse
08f130a0 552 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb
JB
553 connectorId: transactionConnectorId,
554 status: OCPP16ChargePointStatus.AVAILABLE,
555 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
556 });
08f130a0 557 chargingStation.getConnectorStatus(transactionConnectorId).status =
e7aeea18 558 OCPP16ChargePointStatus.AVAILABLE;
c0560973 559 }
08f130a0 560 if (chargingStation.stationInfo.powerSharedByConnectors) {
fa7bccf4 561 chargingStation.powerDivider--;
c0560973 562 }
e7aeea18 563 logger.info(
08f130a0 564 chargingStation.logPrefix() +
e7aeea18
JB
565 ' Transaction ' +
566 requestPayload.transactionId.toString() +
567 ' STOPPED on ' +
08f130a0 568 chargingStation.stationInfo.chargingStationId +
e7aeea18
JB
569 '#' +
570 transactionConnectorId.toString()
571 );
08f130a0 572 chargingStation.resetConnectorStatus(transactionConnectorId);
c0560973 573 } else {
e7aeea18 574 logger.warn(
08f130a0 575 chargingStation.logPrefix() +
e7aeea18
JB
576 ' Stopping transaction id ' +
577 requestPayload.transactionId.toString() +
e8e865ea
JB
578 " REJECTED with status '" +
579 payload.idTagInfo?.status +
580 "'"
e7aeea18 581 );
c0560973
JB
582 }
583 }
584
844e496b
JB
585 private handleResponseStatusNotification(
586 chargingStation: ChargingStation,
587 payload: OCPP16StatusNotificationResponse
588 ): void {
589 this.validateResponsePayload(
590 chargingStation,
591 OCPP16RequestCommand.STATUS_NOTIFICATION,
592 this.statusNotificationResponseJsonSchema,
593 payload
594 );
595 }
c0560973 596
844e496b
JB
597 private handleResponseMeterValues(
598 chargingStation: ChargingStation,
599 payload: OCPP16MeterValuesResponse
600 ): void {
601 this.validateResponsePayload(
602 chargingStation,
603 OCPP16RequestCommand.METER_VALUES,
604 this.meterValuesResponseJsonSchema,
605 payload
606 );
607 }
c0560973 608}