build(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ResponseService.ts
CommitLineData
edd13439 1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
c8eeb62b 2
6c1761d4 3import type { JSONSchemaType } from 'ajv';
844e496b 4
2896e06d 5import { type ChargingStation, ChargingStationConfigurationUtils } from '../../../charging-station';
268a74bb 6import { OCPPError } from '../../../exception';
ef6fa3fb 7import {
268a74bb
JB
8 type ChangeAvailabilityResponse,
9 type ChangeConfigurationResponse,
10 type ClearChargingProfileResponse,
11 ErrorType,
12 type GenericResponse,
13 type GetConfigurationResponse,
14 type GetDiagnosticsResponse,
15 type JsonObject,
16 type JsonType,
8114d10e 17 OCPP16AuthorizationStatus,
27782dbc
JB
18 type OCPP16AuthorizeRequest,
19 type OCPP16AuthorizeResponse,
268a74bb
JB
20 type OCPP16BootNotificationRequest,
21 type OCPP16BootNotificationResponse,
22 OCPP16ChargePointErrorCode,
23 OCPP16ChargePointStatus,
24 type OCPP16DataTransferResponse,
25 type OCPP16DiagnosticsStatusNotificationResponse,
26 type OCPP16FirmwareStatusNotificationResponse,
41189456 27 type OCPP16GetCompositeScheduleResponse,
268a74bb
JB
28 type OCPP16HeartbeatResponse,
29 OCPP16IncomingRequestCommand,
30 type OCPP16MeterValuesRequest,
31 type OCPP16MeterValuesResponse,
32 OCPP16RequestCommand,
33 OCPP16StandardParametersKey,
27782dbc
JB
34 type OCPP16StartTransactionRequest,
35 type OCPP16StartTransactionResponse,
268a74bb
JB
36 type OCPP16StatusNotificationRequest,
37 type OCPP16StatusNotificationResponse,
27782dbc
JB
38 type OCPP16StopTransactionRequest,
39 type OCPP16StopTransactionResponse,
268a74bb
JB
40 type OCPP16TriggerMessageResponse,
41 type OCPP16UpdateFirmwareResponse,
42 OCPPVersion,
02887891
JB
43 RegistrationStatusEnumType,
44 type ResponseHandler,
268a74bb
JB
45 type SetChargingProfileResponse,
46 type UnlockConnectorResponse,
47} from '../../../types';
60a74391 48import { Constants, Utils, logger } from '../../../utils';
2896e06d 49import { OCPP16ServiceUtils, OCPPResponseService } from '../internal';
c0560973 50
909dcf2d
JB
51const moduleName = 'OCPP16ResponseService';
52
268a74bb 53export class OCPP16ResponseService extends OCPPResponseService {
b3fc3ff5
JB
54 public jsonIncomingRequestResponseSchemas: Map<
55 OCPP16IncomingRequestCommand,
56 JSONSchemaType<JsonObject>
57 >;
58
58144adb 59 private responseHandlers: Map<OCPP16RequestCommand, ResponseHandler>;
b52c969d 60 private jsonSchemas: Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>;
58144adb 61
08f130a0 62 public constructor() {
b768993d
JB
63 // if (new.target?.name === moduleName) {
64 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
65 // }
d270cc87 66 super(OCPPVersion.VERSION_16);
58144adb
JB
67 this.responseHandlers = new Map<OCPP16RequestCommand, ResponseHandler>([
68 [OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)],
b52c969d 69 [OCPP16RequestCommand.HEARTBEAT, this.emptyResponseHandler.bind(this)],
58144adb
JB
70 [OCPP16RequestCommand.AUTHORIZE, this.handleResponseAuthorize.bind(this)],
71 [OCPP16RequestCommand.START_TRANSACTION, this.handleResponseStartTransaction.bind(this)],
72 [OCPP16RequestCommand.STOP_TRANSACTION, this.handleResponseStopTransaction.bind(this)],
b52c969d
JB
73 [OCPP16RequestCommand.STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
74 [OCPP16RequestCommand.METER_VALUES, this.emptyResponseHandler.bind(this)],
75 [OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
91a7d3ea 76 [OCPP16RequestCommand.DATA_TRANSFER, this.emptyResponseHandler.bind(this)],
c9a4f9ea 77 [OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, this.emptyResponseHandler.bind(this)],
b52c969d
JB
78 ]);
79 this.jsonSchemas = new Map<OCPP16RequestCommand, JSONSchemaType<JsonObject>>([
80 [
81 OCPP16RequestCommand.BOOT_NOTIFICATION,
130783a7 82 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16BootNotificationResponse>(
1b271a54
JB
83 '../../../assets/json-schemas/ocpp/1.6/BootNotificationResponse.json',
84 moduleName,
85 'constructor'
e9a4164c 86 ),
b52c969d
JB
87 ],
88 [
89 OCPP16RequestCommand.HEARTBEAT,
130783a7 90 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16HeartbeatResponse>(
1b271a54
JB
91 '../../../assets/json-schemas/ocpp/1.6/HeartbeatResponse.json',
92 moduleName,
93 'constructor'
e9a4164c 94 ),
b52c969d
JB
95 ],
96 [
97 OCPP16RequestCommand.AUTHORIZE,
130783a7 98 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16AuthorizeResponse>(
1b271a54
JB
99 '../../../assets/json-schemas/ocpp/1.6/AuthorizeResponse.json',
100 moduleName,
101 'constructor'
e9a4164c 102 ),
b52c969d
JB
103 ],
104 [
105 OCPP16RequestCommand.START_TRANSACTION,
130783a7 106 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StartTransactionResponse>(
1b271a54
JB
107 '../../../assets/json-schemas/ocpp/1.6/StartTransactionResponse.json',
108 moduleName,
109 'constructor'
e9a4164c 110 ),
b52c969d
JB
111 ],
112 [
113 OCPP16RequestCommand.STOP_TRANSACTION,
130783a7 114 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StopTransactionResponse>(
1b271a54
JB
115 '../../../assets/json-schemas/ocpp/1.6/StopTransactionResponse.json',
116 moduleName,
117 'constructor'
e9a4164c 118 ),
b52c969d
JB
119 ],
120 [
121 OCPP16RequestCommand.STATUS_NOTIFICATION,
130783a7 122 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16StatusNotificationResponse>(
1b271a54
JB
123 '../../../assets/json-schemas/ocpp/1.6/StatusNotificationResponse.json',
124 moduleName,
125 'constructor'
e9a4164c 126 ),
b52c969d
JB
127 ],
128 [
129 OCPP16RequestCommand.METER_VALUES,
130783a7 130 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16MeterValuesResponse>(
1b271a54
JB
131 '../../../assets/json-schemas/ocpp/1.6/MeterValuesResponse.json',
132 moduleName,
133 'constructor'
e9a4164c 134 ),
b52c969d
JB
135 ],
136 [
137 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION,
130783a7 138 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DiagnosticsStatusNotificationResponse>(
1b271a54
JB
139 '../../../assets/json-schemas/ocpp/1.6/DiagnosticsStatusNotificationResponse.json',
140 moduleName,
141 'constructor'
e9a4164c 142 ),
b52c969d 143 ],
91a7d3ea
JB
144 [
145 OCPP16RequestCommand.DATA_TRANSFER,
130783a7 146 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
1b271a54
JB
147 '../../../assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
148 moduleName,
149 'constructor'
e9a4164c 150 ),
91a7d3ea 151 ],
c9a4f9ea
JB
152 [
153 OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION,
130783a7 154 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16FirmwareStatusNotificationResponse>(
1b271a54
JB
155 '../../../assets/json-schemas/ocpp/1.6/FirmwareStatusNotificationResponse.json',
156 moduleName,
157 'constructor'
e9a4164c 158 ),
c9a4f9ea 159 ],
58144adb 160 ]);
02887891
JB
161 this.jsonIncomingRequestResponseSchemas = new Map([
162 [
163 OCPP16IncomingRequestCommand.RESET,
130783a7 164 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
165 '../../../assets/json-schemas/ocpp/1.6/ResetResponse.json',
166 moduleName,
167 'constructor'
e9a4164c 168 ),
02887891
JB
169 ],
170 [
171 OCPP16IncomingRequestCommand.CLEAR_CACHE,
130783a7 172 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
173 '../../../assets/json-schemas/ocpp/1.6/ClearCacheResponse.json',
174 moduleName,
175 'constructor'
e9a4164c 176 ),
02887891
JB
177 ],
178 [
179 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
130783a7 180 OCPP16ServiceUtils.parseJsonSchemaFile<ChangeAvailabilityResponse>(
1b271a54
JB
181 '../../../assets/json-schemas/ocpp/1.6/ChangeAvailabilityResponse.json',
182 moduleName,
183 'constructor'
e9a4164c 184 ),
02887891
JB
185 ],
186 [
187 OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
130783a7 188 OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorResponse>(
1b271a54
JB
189 '../../../assets/json-schemas/ocpp/1.6/UnlockConnectorResponse.json',
190 moduleName,
191 'constructor'
e9a4164c 192 ),
02887891
JB
193 ],
194 [
195 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
130783a7 196 OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationResponse>(
1b271a54
JB
197 '../../../assets/json-schemas/ocpp/1.6/GetConfigurationResponse.json',
198 moduleName,
199 'constructor'
e9a4164c 200 ),
02887891
JB
201 ],
202 [
203 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
130783a7 204 OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationResponse>(
1b271a54
JB
205 '../../../assets/json-schemas/ocpp/1.6/ChangeConfigurationResponse.json',
206 moduleName,
207 'constructor'
e9a4164c 208 ),
02887891 209 ],
41189456
JB
210 [
211 OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
212 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleResponse>(
213 '../../../assets/json-schemas/ocpp/1.6/GetCompositeScheduleResponse.json',
214 moduleName,
215 'constructor'
216 ),
217 ],
02887891
JB
218 [
219 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
130783a7 220 OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileResponse>(
1b271a54
JB
221 '../../../assets/json-schemas/ocpp/1.6/SetChargingProfileResponse.json',
222 moduleName,
223 'constructor'
e9a4164c 224 ),
02887891
JB
225 ],
226 [
227 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
130783a7 228 OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileResponse>(
1b271a54
JB
229 '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfileResponse.json',
230 moduleName,
231 'constructor'
e9a4164c 232 ),
02887891
JB
233 ],
234 [
235 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
130783a7 236 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
237 '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransactionResponse.json',
238 moduleName,
239 'constructor'
e9a4164c 240 ),
02887891
JB
241 ],
242 [
243 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
130783a7 244 OCPP16ServiceUtils.parseJsonSchemaFile<GenericResponse>(
1b271a54
JB
245 '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransactionResponse.json',
246 moduleName,
247 'constructor'
e9a4164c 248 ),
02887891
JB
249 ],
250 [
251 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
130783a7 252 OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsResponse>(
1b271a54
JB
253 '../../../assets/json-schemas/ocpp/1.6/GetDiagnosticsResponse.json',
254 moduleName,
255 'constructor'
e9a4164c 256 ),
02887891
JB
257 ],
258 [
259 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
130783a7 260 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageResponse>(
1b271a54
JB
261 '../../../assets/json-schemas/ocpp/1.6/TriggerMessageResponse.json',
262 moduleName,
263 'constructor'
e9a4164c 264 ),
02887891
JB
265 ],
266 [
267 OCPP16IncomingRequestCommand.DATA_TRANSFER,
130783a7 268 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferResponse>(
1b271a54
JB
269 '../../../assets/json-schemas/ocpp/1.6/DataTransferResponse.json',
270 moduleName,
271 'constructor'
e9a4164c 272 ),
02887891
JB
273 ],
274 [
275 OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
130783a7 276 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareResponse>(
1b271a54
JB
277 '../../../assets/json-schemas/ocpp/1.6/UpdateFirmwareResponse.json',
278 moduleName,
279 'constructor'
e9a4164c 280 ),
02887891
JB
281 ],
282 ]);
31f59c6d
JB
283 this.validatePayload = this.validatePayload.bind(this) as (
284 chargingStation: ChargingStation,
285 commandName: OCPP16RequestCommand,
286 payload: JsonType
287 ) => boolean;
58144adb
JB
288 }
289
f7f98c68 290 public async responseHandler(
08f130a0 291 chargingStation: ChargingStation,
e7aeea18 292 commandName: OCPP16RequestCommand,
5cc4b63b
JB
293 payload: JsonType,
294 requestPayload: JsonType
e7aeea18 295 ): Promise<void> {
ed6cfcff
JB
296 if (
297 chargingStation.isRegistered() === true ||
298 commandName === OCPP16RequestCommand.BOOT_NOTIFICATION
299 ) {
65554cc3 300 if (
ed6cfcff
JB
301 this.responseHandlers.has(commandName) === true &&
302 OCPP16ServiceUtils.isRequestCommandSupported(chargingStation, commandName) === true
65554cc3 303 ) {
124f3553 304 try {
9c5c4195 305 this.validatePayload(chargingStation, commandName, payload);
08f130a0 306 await this.responseHandlers.get(commandName)(chargingStation, payload, requestPayload);
124f3553 307 } catch (error) {
6c8f5d90
JB
308 logger.error(
309 `${chargingStation.logPrefix()} ${moduleName}.responseHandler: Handle response error:`,
310 error
311 );
124f3553
JB
312 throw error;
313 }
314 } else {
315 // Throw exception
e7aeea18
JB
316 throw new OCPPError(
317 ErrorType.NOT_IMPLEMENTED,
6c8f5d90 318 `${commandName} is not implemented to handle response PDU ${JSON.stringify(
e7aeea18
JB
319 payload,
320 null,
321 2
322 )}`,
7369e417
JB
323 commandName,
324 payload
e7aeea18 325 );
887fef76 326 }
c0560973 327 } else {
e7aeea18
JB
328 throw new OCPPError(
329 ErrorType.SECURITY_ERROR,
6c8f5d90 330 `${commandName} cannot be issued to handle response PDU ${JSON.stringify(
e7aeea18
JB
331 payload,
332 null,
333 2
439fc71b 334 )} while the charging station is not registered on the central server.`,
7369e417
JB
335 commandName,
336 payload
e7aeea18 337 );
c0560973
JB
338 }
339 }
340
9c5c4195
JB
341 private validatePayload(
342 chargingStation: ChargingStation,
343 commandName: OCPP16RequestCommand,
344 payload: JsonType
345 ): boolean {
45988780 346 if (this.jsonSchemas.has(commandName) === true) {
9c5c4195
JB
347 return this.validateResponsePayload(
348 chargingStation,
349 commandName,
350 this.jsonSchemas.get(commandName),
351 payload
352 );
353 }
354 logger.warn(
b3fc3ff5 355 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
9c5c4195
JB
356 );
357 return false;
358 }
359
08f130a0
JB
360 private handleResponseBootNotification(
361 chargingStation: ChargingStation,
362 payload: OCPP16BootNotificationResponse
363 ): void {
d270cc87 364 if (payload.status === RegistrationStatusEnumType.ACCEPTED) {
17ac262c
JB
365 ChargingStationConfigurationUtils.addConfigurationKey(
366 chargingStation,
f0f65a62 367 OCPP16StandardParametersKey.HeartbeatInterval,
a95873d8 368 payload.interval.toString(),
abe9e9dd 369 {},
a95873d8 370 { overwrite: true, save: true }
e7aeea18 371 );
17ac262c
JB
372 ChargingStationConfigurationUtils.addConfigurationKey(
373 chargingStation,
f0f65a62 374 OCPP16StandardParametersKey.HeartBeatInterval,
e7aeea18 375 payload.interval.toString(),
00db15b8 376 { visible: false },
a95873d8 377 { overwrite: true, save: true }
e7aeea18 378 );
8f953431 379 OCPP16ServiceUtils.startHeartbeatInterval(chargingStation, payload.interval);
672fed6e 380 }
d270cc87 381 if (Object.values(RegistrationStatusEnumType).includes(payload.status)) {
08f130a0 382 const logMsg = `${chargingStation.logPrefix()} Charging station in '${
e7aeea18
JB
383 payload.status
384 }' state on the central server`;
d270cc87 385 payload.status === RegistrationStatusEnumType.REJECTED
e7aeea18
JB
386 ? logger.warn(logMsg)
387 : logger.info(logMsg);
c0560973 388 } else {
e7aeea18 389 logger.error(
44eb6026 390 `${chargingStation.logPrefix()} Charging station boot notification response received: %j with undefined registration status`,
e7aeea18
JB
391 payload
392 );
c0560973
JB
393 }
394 }
395
e7aeea18 396 private handleResponseAuthorize(
08f130a0 397 chargingStation: ChargingStation,
e7aeea18 398 payload: OCPP16AuthorizeResponse,
ef6fa3fb 399 requestPayload: OCPP16AuthorizeRequest
e7aeea18 400 ): void {
58144adb 401 let authorizeConnectorId: number;
08f130a0 402 for (const connectorId of chargingStation.connectors.keys()) {
e7aeea18
JB
403 if (
404 connectorId > 0 &&
08f130a0 405 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag
e7aeea18 406 ) {
734d790d 407 authorizeConnectorId = connectorId;
58144adb
JB
408 break;
409 }
410 }
9bb1159e 411 const authorizeConnectorIdDefined = !Utils.isNullOrUndefined(authorizeConnectorId);
58144adb 412 if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
44eb6026 413 authorizeConnectorIdDefined &&
1984f194 414 (chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true);
e7aeea18 415 logger.debug(
1984f194 416 `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' accepted${
44eb6026 417 authorizeConnectorIdDefined ? ` on connector ${authorizeConnectorId}` : ''
1984f194 418 }`
e7aeea18 419 );
58144adb 420 } else {
44eb6026 421 if (authorizeConnectorIdDefined) {
1984f194 422 chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false;
d812bdcb 423 delete chargingStation.getConnectorStatus(authorizeConnectorId)?.authorizeIdTag;
1984f194 424 }
e7aeea18 425 logger.debug(
1984f194 426 `${chargingStation.logPrefix()} IdTag '${requestPayload.idTag}' rejected with status '${
e7aeea18 427 payload.idTagInfo.status
44eb6026 428 }'${authorizeConnectorIdDefined ? ` on connector ${authorizeConnectorId}` : ''}`
e7aeea18 429 );
58144adb
JB
430 }
431 }
432
e7aeea18 433 private async handleResponseStartTransaction(
08f130a0 434 chargingStation: ChargingStation,
e7aeea18 435 payload: OCPP16StartTransactionResponse,
ef6fa3fb 436 requestPayload: OCPP16StartTransactionRequest
e7aeea18 437 ): Promise<void> {
c0560973
JB
438 const connectorId = requestPayload.connectorId;
439
440 let transactionConnectorId: number;
08f130a0 441 for (const id of chargingStation.connectors.keys()) {
734d790d
JB
442 if (id > 0 && id === connectorId) {
443 transactionConnectorId = id;
c0560973
JB
444 break;
445 }
446 }
72092cfc 447 if (Utils.isNullOrUndefined(transactionConnectorId)) {
e7aeea18 448 logger.error(
44eb6026 449 `${chargingStation.logPrefix()} Trying to start a transaction on a non existing connector Id ${connectorId.toString()}`
e7aeea18 450 );
c0560973
JB
451 return;
452 }
e7aeea18 453 if (
72092cfc 454 chargingStation.getConnectorStatus(connectorId)?.transactionRemoteStarted === true &&
3a13fc92
JB
455 chargingStation.getAuthorizeRemoteTxRequests() === true &&
456 chargingStation.getLocalAuthListEnabled() === true &&
f911a4af 457 chargingStation.hasIdTags() &&
72092cfc 458 chargingStation.getConnectorStatus(connectorId)?.idTagLocalAuthorized === false
e7aeea18
JB
459 ) {
460 logger.error(
44eb6026 461 `${chargingStation.logPrefix()} Trying to start a transaction with a not local authorized idTag ${
72092cfc 462 chargingStation.getConnectorStatus(connectorId)?.localAuthorizeIdTag
44eb6026 463 } on connector Id ${connectorId.toString()}`
e7aeea18 464 );
08f130a0 465 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
466 return;
467 }
e7aeea18 468 if (
72092cfc 469 chargingStation.getConnectorStatus(connectorId)?.transactionRemoteStarted === true &&
3a13fc92
JB
470 chargingStation.getAuthorizeRemoteTxRequests() === true &&
471 chargingStation.getMustAuthorizeAtRemoteStart() === true &&
72092cfc
JB
472 chargingStation.getConnectorStatus(connectorId)?.idTagLocalAuthorized === false &&
473 chargingStation.getConnectorStatus(connectorId)?.idTagAuthorized === false
e7aeea18
JB
474 ) {
475 logger.error(
44eb6026 476 `${chargingStation.logPrefix()} Trying to start a transaction with a not authorized idTag ${
72092cfc 477 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag
44eb6026 478 } on connector Id ${connectorId.toString()}`
e7aeea18 479 );
08f130a0 480 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
481 return;
482 }
e7aeea18 483 if (
72092cfc
JB
484 chargingStation.getConnectorStatus(connectorId)?.idTagAuthorized &&
485 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag !== requestPayload.idTag
e7aeea18
JB
486 ) {
487 logger.error(
44eb6026
JB
488 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
489 requestPayload.idTag
490 } different from the authorize request one ${
72092cfc 491 chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag
44eb6026 492 } on connector Id ${connectorId.toString()}`
e7aeea18 493 );
08f130a0 494 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
495 return;
496 }
e7aeea18 497 if (
72092cfc
JB
498 chargingStation.getConnectorStatus(connectorId)?.idTagLocalAuthorized &&
499 chargingStation.getConnectorStatus(connectorId)?.localAuthorizeIdTag !== requestPayload.idTag
e7aeea18
JB
500 ) {
501 logger.error(
44eb6026
JB
502 `${chargingStation.logPrefix()} Trying to start a transaction with an idTag ${
503 requestPayload.idTag
504 } different from the local authorized one ${
72092cfc 505 chargingStation.getConnectorStatus(connectorId)?.localAuthorizeIdTag
44eb6026 506 } on connector Id ${connectorId.toString()}`
e7aeea18 507 );
08f130a0 508 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
163547b1
JB
509 return;
510 }
5e3cb728 511 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
e7aeea18 512 logger.debug(
44eb6026 513 `${chargingStation.logPrefix()} Trying to start a transaction on an already used connector ${connectorId.toString()}: %j`,
08f130a0 514 chargingStation.getConnectorStatus(connectorId)
e7aeea18 515 );
c0560973
JB
516 return;
517 }
e7aeea18 518 if (
08f130a0 519 chargingStation.getConnectorStatus(connectorId)?.status !==
721646e9
JB
520 OCPP16ChargePointStatus.Available &&
521 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Preparing
e7aeea18
JB
522 ) {
523 logger.error(
08f130a0
JB
524 `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${
525 chargingStation.getConnectorStatus(connectorId)?.status
e7aeea18
JB
526 }`
527 );
290d006c
JB
528 return;
529 }
fc040c43
JB
530 // if (!Number.isInteger(payload.transactionId)) {
531 // logger.warn(
532 // `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${
533 // payload.transactionId
534 // }, converting to integer`
535 // );
536 // payload.transactionId = Utils.convertToInt(payload.transactionId);
537 // }
c0560973 538
f0c6ed89 539 if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
08f130a0
JB
540 chargingStation.getConnectorStatus(connectorId).transactionStarted = true;
541 chargingStation.getConnectorStatus(connectorId).transactionId = payload.transactionId;
542 chargingStation.getConnectorStatus(connectorId).transactionIdTag = requestPayload.idTag;
543 chargingStation.getConnectorStatus(
e7aeea18
JB
544 connectorId
545 ).transactionEnergyActiveImportRegisterValue = 0;
08f130a0 546 chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue =
e7aeea18 547 OCPP16ServiceUtils.buildTransactionBeginMeterValue(
08f130a0 548 chargingStation,
e7aeea18
JB
549 connectorId,
550 requestPayload.meterStart
551 );
08f130a0
JB
552 chargingStation.getBeginEndMeterValues() &&
553 (await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
554 OCPP16MeterValuesRequest,
555 OCPP16MeterValuesResponse
08f130a0 556 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
93b4a429 557 connectorId,
ef6fa3fb 558 transactionId: payload.transactionId,
7369e417 559 meterValue: [chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue],
ef6fa3fb 560 }));
08f130a0 561 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
562 OCPP16StatusNotificationRequest,
563 OCPP16StatusNotificationResponse
08f130a0 564 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 565 connectorId,
721646e9 566 status: OCPP16ChargePointStatus.Charging,
ef6fa3fb
JB
567 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
568 });
721646e9 569 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Charging;
e7aeea18 570 logger.info(
44eb6026
JB
571 `${chargingStation.logPrefix()} Transaction ${payload.transactionId.toString()} STARTED on ${
572 chargingStation.stationInfo.chargingStationId
573 }#${connectorId.toString()} for idTag '${requestPayload.idTag}'`
e7aeea18 574 );
08f130a0 575 if (chargingStation.stationInfo.powerSharedByConnectors) {
fa7bccf4 576 chargingStation.powerDivider++;
c0560973 577 }
17ac262c
JB
578 const configuredMeterValueSampleInterval =
579 ChargingStationConfigurationUtils.getConfigurationKey(
580 chargingStation,
581 OCPP16StandardParametersKey.MeterValueSampleInterval
582 );
08f130a0 583 chargingStation.startMeterValues(
e7aeea18
JB
584 connectorId,
585 configuredMeterValueSampleInterval
586 ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000
d3195f0a 587 : Constants.DEFAULT_METER_VALUES_INTERVAL
e7aeea18 588 );
c0560973 589 } else {
e7aeea18 590 logger.warn(
44eb6026
JB
591 `${chargingStation.logPrefix()} Starting transaction id ${payload.transactionId.toString()} REJECTED with status '${
592 payload.idTagInfo?.status
593 }', idTag '${requestPayload.idTag}'`
e7aeea18 594 );
08f130a0 595 await this.resetConnectorOnStartTransactionError(chargingStation, connectorId);
a2653482
JB
596 }
597 }
598
08f130a0
JB
599 private async resetConnectorOnStartTransactionError(
600 chargingStation: ChargingStation,
601 connectorId: number
602 ): Promise<void> {
603 chargingStation.resetConnectorStatus(connectorId);
e7aeea18 604 if (
721646e9 605 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Available
e7aeea18 606 ) {
08f130a0 607 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
608 OCPP16StatusNotificationRequest,
609 OCPP16StatusNotificationResponse
08f130a0 610 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 611 connectorId,
721646e9 612 status: OCPP16ChargePointStatus.Available,
ef6fa3fb
JB
613 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
614 });
721646e9 615 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Available;
c0560973
JB
616 }
617 }
618
e7aeea18 619 private async handleResponseStopTransaction(
08f130a0 620 chargingStation: ChargingStation,
e7aeea18 621 payload: OCPP16StopTransactionResponse,
ef6fa3fb 622 requestPayload: OCPP16StopTransactionRequest
e7aeea18 623 ): Promise<void> {
08f130a0 624 const transactionConnectorId = chargingStation.getConnectorIdByTransactionId(
f479a792
JB
625 requestPayload.transactionId
626 );
d812bdcb 627 if (Utils.isNullOrUndefined(transactionConnectorId)) {
e7aeea18 628 logger.error(
44eb6026 629 `${chargingStation.logPrefix()} Trying to stop a non existing transaction ${requestPayload.transactionId.toString()}`
e7aeea18 630 );
c0560973
JB
631 return;
632 }
2cace1a5
JB
633 chargingStation.getBeginEndMeterValues() === true &&
634 chargingStation.getOcppStrictCompliance() === false &&
635 chargingStation.getOutOfOrderEndMeterValues() === true &&
636 (await chargingStation.ocppRequestService.requestHandler<
637 OCPP16MeterValuesRequest,
638 OCPP16MeterValuesResponse
639 >(chargingStation, OCPP16RequestCommand.METER_VALUES, {
640 connectorId: transactionConnectorId,
641 transactionId: requestPayload.transactionId,
642 meterValue: [
643 OCPP16ServiceUtils.buildTransactionEndMeterValue(
644 chargingStation,
645 transactionConnectorId,
646 requestPayload.meterStop
647 ),
648 ],
649 }));
650 if (
651 chargingStation.isChargingStationAvailable() === false ||
652 chargingStation.isConnectorAvailable(transactionConnectorId) === false
653 ) {
654 await chargingStation.ocppRequestService.requestHandler<
655 OCPP16StatusNotificationRequest,
656 OCPP16StatusNotificationResponse
657 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
658 connectorId: transactionConnectorId,
721646e9 659 status: OCPP16ChargePointStatus.Unavailable,
2cace1a5
JB
660 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
661 });
662 chargingStation.getConnectorStatus(transactionConnectorId).status =
721646e9 663 OCPP16ChargePointStatus.Unavailable;
c0560973 664 } else {
2cace1a5
JB
665 await chargingStation.ocppRequestService.requestHandler<
666 OCPP16BootNotificationRequest,
667 OCPP16BootNotificationResponse
668 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
669 connectorId: transactionConnectorId,
721646e9 670 status: OCPP16ChargePointStatus.Available,
2cace1a5
JB
671 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
672 });
673 chargingStation.getConnectorStatus(transactionConnectorId).status =
721646e9 674 OCPP16ChargePointStatus.Available;
2cace1a5
JB
675 }
676 if (chargingStation.stationInfo.powerSharedByConnectors) {
677 chargingStation.powerDivider--;
678 }
679 chargingStation.resetConnectorStatus(transactionConnectorId);
8ca6874c
JB
680 const logMsg = `${chargingStation.logPrefix()} Transaction ${requestPayload.transactionId.toString()} STOPPED on ${
681 chargingStation.stationInfo.chargingStationId
d812bdcb 682 }#${transactionConnectorId?.toString()} with status '${
8ca6874c
JB
683 payload.idTagInfo?.status ?? 'undefined'
684 }'`;
2cace1a5
JB
685 if (
686 Utils.isNullOrUndefined(payload.idTagInfo) ||
687 payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED
688 ) {
689 logger.info(logMsg);
690 } else {
691 logger.warn(logMsg);
c0560973
JB
692 }
693 }
c0560973 694}