build(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
CommitLineData
edd13439 1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
c8eeb62b 2
130783a7
JB
3import fs from 'node:fs';
4import path from 'node:path';
5import { URL, fileURLToPath } from 'node:url';
8114d10e 6
6c1761d4 7import type { JSONSchemaType } from 'ajv';
27782dbc 8import { Client, type FTPResponse } from 'basic-ftp';
8114d10e
JB
9import tar from 'tar';
10
2896e06d
JB
11import {
12 type ChargingStation,
13 ChargingStationConfigurationUtils,
14 ChargingStationUtils,
15} from '../../../charging-station';
268a74bb 16import { OCPPError } from '../../../exception';
e7aeea18 17import {
27782dbc 18 type ChangeAvailabilityRequest,
268a74bb 19 type ChangeAvailabilityResponse,
27782dbc 20 type ChangeConfigurationRequest,
268a74bb 21 type ChangeConfigurationResponse,
27782dbc 22 type ClearChargingProfileRequest,
268a74bb
JB
23 type ClearChargingProfileResponse,
24 ErrorType,
25 type GenericResponse,
41189456 26 GenericStatus,
27782dbc 27 type GetConfigurationRequest,
268a74bb 28 type GetConfigurationResponse,
27782dbc 29 type GetDiagnosticsRequest,
268a74bb
JB
30 type GetDiagnosticsResponse,
31 type IncomingRequestHandler,
32 type JsonObject,
33 type JsonType,
34 OCPP16AuthorizationStatus,
35 type OCPP16AuthorizeRequest,
36 type OCPP16AuthorizeResponse,
e7aeea18 37 OCPP16AvailabilityType,
27782dbc 38 type OCPP16BootNotificationRequest,
268a74bb
JB
39 type OCPP16BootNotificationResponse,
40 OCPP16ChargePointErrorCode,
41 OCPP16ChargePointStatus,
42 type OCPP16ChargingProfile,
0ac97927 43 OCPP16ChargingProfilePurposeType,
41189456 44 type OCPP16ChargingSchedule,
27782dbc
JB
45 type OCPP16ClearCacheRequest,
46 type OCPP16DataTransferRequest,
268a74bb
JB
47 type OCPP16DataTransferResponse,
48 OCPP16DataTransferStatus,
77b95a89 49 OCPP16DataTransferVendorId,
268a74bb 50 OCPP16DiagnosticsStatus,
c9a4f9ea 51 type OCPP16DiagnosticsStatusNotificationRequest,
268a74bb 52 type OCPP16DiagnosticsStatusNotificationResponse,
c9a4f9ea
JB
53 OCPP16FirmwareStatus,
54 type OCPP16FirmwareStatusNotificationRequest,
268a74bb 55 type OCPP16FirmwareStatusNotificationResponse,
41189456
JB
56 type OCPP16GetCompositeScheduleRequest,
57 type OCPP16GetCompositeScheduleResponse,
27782dbc 58 type OCPP16HeartbeatRequest,
268a74bb 59 type OCPP16HeartbeatResponse,
e7aeea18 60 OCPP16IncomingRequestCommand,
c60ed4b8 61 OCPP16MessageTrigger,
94a464f9 62 OCPP16RequestCommand,
268a74bb
JB
63 OCPP16StandardParametersKey,
64 type OCPP16StartTransactionRequest,
65 type OCPP16StartTransactionResponse,
27782dbc 66 type OCPP16StatusNotificationRequest,
268a74bb
JB
67 type OCPP16StatusNotificationResponse,
68 OCPP16StopTransactionReason,
69 OCPP16SupportedFeatureProfiles,
27782dbc 70 type OCPP16TriggerMessageRequest,
268a74bb 71 type OCPP16TriggerMessageResponse,
27782dbc 72 type OCPP16UpdateFirmwareRequest,
268a74bb
JB
73 type OCPP16UpdateFirmwareResponse,
74 type OCPPConfigurationKey,
75 OCPPVersion,
27782dbc
JB
76 type RemoteStartTransactionRequest,
77 type RemoteStopTransactionRequest,
78 type ResetRequest,
79 type SetChargingProfileRequest,
27782dbc 80 type SetChargingProfileResponse,
268a74bb 81 type UnlockConnectorRequest,
27782dbc 82 type UnlockConnectorResponse,
268a74bb 83} from '../../../types';
60a74391 84import { Constants, Utils, logger } from '../../../utils';
2896e06d 85import { OCPP16ServiceUtils, OCPPConstants, OCPPIncomingRequestService } from '../internal';
c0560973 86
2a115f87 87const moduleName = 'OCPP16IncomingRequestService';
909dcf2d 88
268a74bb 89export class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
b3fc3ff5 90 protected jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>;
58144adb
JB
91 private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
92
08f130a0 93 public constructor() {
b768993d
JB
94 // if (new.target?.name === moduleName) {
95 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
96 // }
d270cc87 97 super(OCPPVersion.VERSION_16);
58144adb
JB
98 this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
99 [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
100 [OCPP16IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)],
101 [OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR, this.handleRequestUnlockConnector.bind(this)],
e7aeea18
JB
102 [
103 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
104 this.handleRequestGetConfiguration.bind(this),
105 ],
106 [
107 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
108 this.handleRequestChangeConfiguration.bind(this),
109 ],
41189456
JB
110 [
111 OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
112 this.handleRequestGetCompositeSchedule.bind(this),
113 ],
e7aeea18
JB
114 [
115 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
116 this.handleRequestSetChargingProfile.bind(this),
117 ],
118 [
119 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
120 this.handleRequestClearChargingProfile.bind(this),
121 ],
122 [
123 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
124 this.handleRequestChangeAvailability.bind(this),
125 ],
126 [
127 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
128 this.handleRequestRemoteStartTransaction.bind(this),
129 ],
130 [
131 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
132 this.handleRequestRemoteStopTransaction.bind(this),
133 ],
734d790d 134 [OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, this.handleRequestGetDiagnostics.bind(this)],
e7aeea18 135 [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)],
77b95a89 136 [OCPP16IncomingRequestCommand.DATA_TRANSFER, this.handleRequestDataTransfer.bind(this)],
c9a4f9ea 137 [OCPP16IncomingRequestCommand.UPDATE_FIRMWARE, this.handleRequestUpdateFirmware.bind(this)],
58144adb 138 ]);
b52c969d
JB
139 this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>([
140 [
141 OCPP16IncomingRequestCommand.RESET,
130783a7 142 OCPP16ServiceUtils.parseJsonSchemaFile<ResetRequest>(
1b271a54
JB
143 '../../../assets/json-schemas/ocpp/1.6/Reset.json',
144 moduleName,
145 'constructor'
130783a7 146 ),
b52c969d
JB
147 ],
148 [
149 OCPP16IncomingRequestCommand.CLEAR_CACHE,
130783a7 150 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16ClearCacheRequest>(
1b271a54
JB
151 '../../../assets/json-schemas/ocpp/1.6/ClearCache.json',
152 moduleName,
153 'constructor'
e9a4164c 154 ),
b52c969d
JB
155 ],
156 [
157 OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
130783a7 158 OCPP16ServiceUtils.parseJsonSchemaFile<UnlockConnectorRequest>(
1b271a54
JB
159 '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json',
160 moduleName,
161 'constructor'
e9a4164c 162 ),
b52c969d
JB
163 ],
164 [
165 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
130783a7 166 OCPP16ServiceUtils.parseJsonSchemaFile<GetConfigurationRequest>(
1b271a54
JB
167 '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json',
168 moduleName,
169 'constructor'
e9a4164c 170 ),
b52c969d
JB
171 ],
172 [
173 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
130783a7 174 OCPP16ServiceUtils.parseJsonSchemaFile<ChangeConfigurationRequest>(
1b271a54
JB
175 '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
176 moduleName,
177 'constructor'
e9a4164c 178 ),
b52c969d
JB
179 ],
180 [
181 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
130783a7 182 OCPP16ServiceUtils.parseJsonSchemaFile<GetDiagnosticsRequest>(
1b271a54
JB
183 '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
184 moduleName,
185 'constructor'
e9a4164c 186 ),
b52c969d 187 ],
41189456
JB
188 [
189 OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE,
190 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16GetCompositeScheduleRequest>(
191 '../../../assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
192 moduleName,
193 'constructor'
194 ),
195 ],
b52c969d
JB
196 [
197 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
130783a7 198 OCPP16ServiceUtils.parseJsonSchemaFile<SetChargingProfileRequest>(
1b271a54
JB
199 '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
200 moduleName,
201 'constructor'
e9a4164c 202 ),
b52c969d
JB
203 ],
204 [
205 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
130783a7 206 OCPP16ServiceUtils.parseJsonSchemaFile<ClearChargingProfileRequest>(
1b271a54
JB
207 '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
208 moduleName,
209 'constructor'
e9a4164c 210 ),
b52c969d
JB
211 ],
212 [
213 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
130783a7 214 OCPP16ServiceUtils.parseJsonSchemaFile<ChangeAvailabilityRequest>(
1b271a54
JB
215 '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
216 moduleName,
217 'constructor'
e9a4164c 218 ),
b52c969d
JB
219 ],
220 [
221 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
130783a7 222 OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStartTransactionRequest>(
1b271a54
JB
223 '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
224 moduleName,
225 'constructor'
e9a4164c 226 ),
b52c969d
JB
227 ],
228 [
229 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
130783a7 230 OCPP16ServiceUtils.parseJsonSchemaFile<RemoteStopTransactionRequest>(
1b271a54
JB
231 '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
232 moduleName,
233 'constructor'
e9a4164c 234 ),
b52c969d
JB
235 ],
236 [
237 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
130783a7 238 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16TriggerMessageRequest>(
1b271a54
JB
239 '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json',
240 moduleName,
241 'constructor'
e9a4164c 242 ),
b52c969d 243 ],
77b95a89
JB
244 [
245 OCPP16IncomingRequestCommand.DATA_TRANSFER,
130783a7 246 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16DataTransferRequest>(
1b271a54
JB
247 '../../../assets/json-schemas/ocpp/1.6/DataTransfer.json',
248 moduleName,
249 'constructor'
e9a4164c 250 ),
77b95a89 251 ],
bfbda738
JB
252 [
253 OCPP16IncomingRequestCommand.UPDATE_FIRMWARE,
130783a7 254 OCPP16ServiceUtils.parseJsonSchemaFile<OCPP16UpdateFirmwareRequest>(
1b271a54
JB
255 '../../../assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
256 moduleName,
257 'constructor'
e9a4164c 258 ),
bfbda738 259 ],
b52c969d 260 ]);
31f59c6d
JB
261 this.validatePayload = this.validatePayload.bind(this) as (
262 chargingStation: ChargingStation,
263 commandName: OCPP16IncomingRequestCommand,
264 commandPayload: JsonType
265 ) => boolean;
58144adb
JB
266 }
267
f7f98c68 268 public async incomingRequestHandler(
08f130a0 269 chargingStation: ChargingStation,
e7aeea18
JB
270 messageId: string,
271 commandName: OCPP16IncomingRequestCommand,
5cc4b63b 272 commandPayload: JsonType
e7aeea18 273 ): Promise<void> {
5cc4b63b 274 let response: JsonType;
e7aeea18 275 if (
3a13fc92
JB
276 chargingStation.getOcppStrictCompliance() === true &&
277 chargingStation.isInPendingState() === true &&
e7aeea18
JB
278 (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION ||
279 commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)
280 ) {
281 throw new OCPPError(
282 ErrorType.SECURITY_ERROR,
e3018bc4 283 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
e7aeea18
JB
284 commandPayload,
285 null,
286 2
287 )} while the charging station is in pending state on the central server`,
7369e417
JB
288 commandName,
289 commandPayload
e7aeea18 290 );
caad9d6b 291 }
e7aeea18 292 if (
ed6cfcff
JB
293 chargingStation.isRegistered() === true ||
294 (chargingStation.getOcppStrictCompliance() === false &&
295 chargingStation.isInUnknownState() === true)
e7aeea18 296 ) {
65554cc3 297 if (
ed6cfcff
JB
298 this.incomingRequestHandlers.has(commandName) === true &&
299 OCPP16ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName) === true
65554cc3 300 ) {
124f3553 301 try {
9c5c4195 302 this.validatePayload(chargingStation, commandName, commandPayload);
c75a6675 303 // Call the method to build the response
08f130a0
JB
304 response = await this.incomingRequestHandlers.get(commandName)(
305 chargingStation,
306 commandPayload
307 );
124f3553
JB
308 } catch (error) {
309 // Log
6c8f5d90
JB
310 logger.error(
311 `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
312 error
313 );
124f3553
JB
314 throw error;
315 }
316 } else {
317 // Throw exception
e7aeea18
JB
318 throw new OCPPError(
319 ErrorType.NOT_IMPLEMENTED,
e3018bc4 320 `${commandName} is not implemented to handle request PDU ${JSON.stringify(
e7aeea18
JB
321 commandPayload,
322 null,
323 2
324 )}`,
7369e417
JB
325 commandName,
326 commandPayload
e7aeea18 327 );
c0560973
JB
328 }
329 } else {
e7aeea18
JB
330 throw new OCPPError(
331 ErrorType.SECURITY_ERROR,
e3018bc4 332 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
e7aeea18
JB
333 commandPayload,
334 null,
335 2
336 )} while the charging station is not registered on the central server.`,
7369e417
JB
337 commandName,
338 commandPayload
e7aeea18 339 );
c0560973 340 }
c75a6675 341 // Send the built response
08f130a0
JB
342 await chargingStation.ocppRequestService.sendResponse(
343 chargingStation,
344 messageId,
345 response,
346 commandName
347 );
c0560973
JB
348 }
349
9c5c4195
JB
350 private validatePayload(
351 chargingStation: ChargingStation,
352 commandName: OCPP16IncomingRequestCommand,
353 commandPayload: JsonType
354 ): boolean {
45988780 355 if (this.jsonSchemas.has(commandName) === true) {
9c5c4195
JB
356 return this.validateIncomingRequestPayload(
357 chargingStation,
358 commandName,
359 this.jsonSchemas.get(commandName),
360 commandPayload
361 );
362 }
363 logger.warn(
b3fc3ff5 364 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
9c5c4195
JB
365 );
366 return false;
367 }
368
c0560973 369 // Simulate charging station restart
08f130a0
JB
370 private handleRequestReset(
371 chargingStation: ChargingStation,
372 commandPayload: ResetRequest
f03e1042 373 ): GenericResponse {
27f08ad3
JB
374 this.runInAsyncScope(
375 chargingStation.reset.bind(chargingStation) as (
376 this: ChargingStation,
377 ...args: any[]
378 ) => Promise<void>,
379 chargingStation,
380 `${commandPayload.type}Reset` as OCPP16StopTransactionReason
59b6ed8d 381 ).catch(Constants.EMPTY_FUNCTION);
e7aeea18 382 logger.info(
08f130a0 383 `${chargingStation.logPrefix()} ${
e7aeea18
JB
384 commandPayload.type
385 } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
08f130a0 386 chargingStation.stationInfo.resetTime
e7aeea18
JB
387 )}`
388 );
bf53cadf 389 return OCPPConstants.OCPP_RESPONSE_ACCEPTED;
c0560973
JB
390 }
391
e7aeea18 392 private async handleRequestUnlockConnector(
08f130a0 393 chargingStation: ChargingStation,
e7aeea18
JB
394 commandPayload: UnlockConnectorRequest
395 ): Promise<UnlockConnectorResponse> {
c0560973 396 const connectorId = commandPayload.connectorId;
c60ed4b8
JB
397 if (chargingStation.connectors.has(connectorId) === false) {
398 logger.error(
399 `${chargingStation.logPrefix()} Trying to unlock a non existing connector Id ${connectorId.toString()}`
400 );
bf53cadf 401 return OCPPConstants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
c60ed4b8 402 }
c0560973 403 if (connectorId === 0) {
e7aeea18 404 logger.error(
44eb6026 405 `${chargingStation.logPrefix()} Trying to unlock connector Id ${connectorId.toString()}`
e7aeea18 406 );
bf53cadf 407 return OCPPConstants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
c0560973 408 }
5e3cb728
JB
409 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
410 const stopResponse = await chargingStation.stopTransactionOnConnector(
411 connectorId,
412 OCPP16StopTransactionReason.UNLOCK_COMMAND
413 );
c0560973 414 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
bf53cadf 415 return OCPPConstants.OCPP_RESPONSE_UNLOCKED;
c0560973 416 }
bf53cadf 417 return OCPPConstants.OCPP_RESPONSE_UNLOCK_FAILED;
c0560973 418 }
08f130a0 419 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
420 OCPP16StatusNotificationRequest,
421 OCPP16StatusNotificationResponse
08f130a0 422 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 423 connectorId,
721646e9 424 status: OCPP16ChargePointStatus.Available,
ef6fa3fb
JB
425 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
426 });
721646e9 427 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Available;
bf53cadf 428 return OCPPConstants.OCPP_RESPONSE_UNLOCKED;
c0560973
JB
429 }
430
e7aeea18 431 private handleRequestGetConfiguration(
08f130a0 432 chargingStation: ChargingStation,
e7aeea18
JB
433 commandPayload: GetConfigurationRequest
434 ): GetConfigurationResponse {
c0560973
JB
435 const configurationKey: OCPPConfigurationKey[] = [];
436 const unknownKey: string[] = [];
9a15316c 437 if (Utils.isUndefined(commandPayload.key) === true) {
08f130a0 438 for (const configuration of chargingStation.ocppConfiguration.configurationKey) {
a723e7e9 439 if (Utils.isUndefined(configuration.visible) === true) {
7f7b65ca 440 configuration.visible = true;
c0560973 441 }
da8629bb 442 if (configuration.visible === false) {
c0560973
JB
443 continue;
444 }
445 configurationKey.push({
7f7b65ca
JB
446 key: configuration.key,
447 readonly: configuration.readonly,
448 value: configuration.value,
c0560973
JB
449 });
450 }
9a15316c 451 } else if (Utils.isNotEmptyArray(commandPayload.key) === true) {
c0560973 452 for (const key of commandPayload.key) {
17ac262c
JB
453 const keyFound = ChargingStationConfigurationUtils.getConfigurationKey(
454 chargingStation,
acda9cab
JB
455 key,
456 true
17ac262c 457 );
c0560973 458 if (keyFound) {
a723e7e9 459 if (Utils.isUndefined(keyFound.visible) === true) {
c0560973
JB
460 keyFound.visible = true;
461 }
a723e7e9 462 if (keyFound.visible === false) {
c0560973
JB
463 continue;
464 }
465 configurationKey.push({
466 key: keyFound.key,
467 readonly: keyFound.readonly,
468 value: keyFound.value,
469 });
470 } else {
471 unknownKey.push(key);
472 }
473 }
474 }
475 return {
476 configurationKey,
477 unknownKey,
478 };
479 }
480
e7aeea18 481 private handleRequestChangeConfiguration(
08f130a0 482 chargingStation: ChargingStation,
e7aeea18
JB
483 commandPayload: ChangeConfigurationRequest
484 ): ChangeConfigurationResponse {
17ac262c
JB
485 const keyToChange = ChargingStationConfigurationUtils.getConfigurationKey(
486 chargingStation,
487 commandPayload.key,
488 true
489 );
c0560973 490 if (!keyToChange) {
bf53cadf 491 return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
c0560973 492 } else if (keyToChange && keyToChange.readonly) {
bf53cadf 493 return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
c0560973 494 } else if (keyToChange && !keyToChange.readonly) {
c0560973 495 let valueChanged = false;
a95873d8 496 if (keyToChange.value !== commandPayload.value) {
17ac262c
JB
497 ChargingStationConfigurationUtils.setConfigurationKeyValue(
498 chargingStation,
499 commandPayload.key,
500 commandPayload.value,
501 true
502 );
c0560973
JB
503 valueChanged = true;
504 }
505 let triggerHeartbeatRestart = false;
506 if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) {
17ac262c
JB
507 ChargingStationConfigurationUtils.setConfigurationKeyValue(
508 chargingStation,
e7aeea18
JB
509 OCPP16StandardParametersKey.HeartbeatInterval,
510 commandPayload.value
511 );
c0560973
JB
512 triggerHeartbeatRestart = true;
513 }
514 if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) {
17ac262c
JB
515 ChargingStationConfigurationUtils.setConfigurationKeyValue(
516 chargingStation,
e7aeea18
JB
517 OCPP16StandardParametersKey.HeartBeatInterval,
518 commandPayload.value
519 );
c0560973
JB
520 triggerHeartbeatRestart = true;
521 }
522 if (triggerHeartbeatRestart) {
08f130a0 523 chargingStation.restartHeartbeat();
c0560973
JB
524 }
525 if (keyToChange.key === OCPP16StandardParametersKey.WebSocketPingInterval && valueChanged) {
08f130a0 526 chargingStation.restartWebSocketPing();
c0560973
JB
527 }
528 if (keyToChange.reboot) {
bf53cadf 529 return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED;
c0560973 530 }
bf53cadf 531 return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED;
c0560973
JB
532 }
533 }
534
e7aeea18 535 private handleRequestSetChargingProfile(
08f130a0 536 chargingStation: ChargingStation,
e7aeea18
JB
537 commandPayload: SetChargingProfileRequest
538 ): SetChargingProfileResponse {
370ae4ee 539 if (
1789ba2c 540 OCPP16ServiceUtils.checkFeatureProfile(
08f130a0 541 chargingStation,
370ae4ee
JB
542 OCPP16SupportedFeatureProfiles.SmartCharging,
543 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE
1789ba2c 544 ) === false
370ae4ee 545 ) {
bf53cadf 546 return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED;
68cb8b91 547 }
1789ba2c 548 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
e7aeea18 549 logger.error(
08f130a0 550 `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${
e7aeea18
JB
551 commandPayload.connectorId
552 }`
553 );
bf53cadf 554 return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
c0560973 555 }
e7aeea18
JB
556 if (
557 commandPayload.csChargingProfiles.chargingProfilePurpose ===
0ac97927 558 OCPP16ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE &&
e7aeea18
JB
559 commandPayload.connectorId !== 0
560 ) {
bf53cadf 561 return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
c0560973 562 }
e7aeea18
JB
563 if (
564 commandPayload.csChargingProfiles.chargingProfilePurpose ===
0ac97927 565 OCPP16ChargingProfilePurposeType.TX_PROFILE &&
e7aeea18 566 (commandPayload.connectorId === 0 ||
5e3cb728
JB
567 chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted ===
568 false)
e7aeea18 569 ) {
db0af086
JB
570 logger.error(
571 `${chargingStation.logPrefix()} Trying to set transaction charging profile(s) on connector ${
572 commandPayload.connectorId
573 } without a started transaction`
574 );
bf53cadf 575 return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
c0560973 576 }
ed3d2808 577 OCPP16ServiceUtils.setChargingProfile(
7cb5b17f 578 chargingStation,
e7aeea18
JB
579 commandPayload.connectorId,
580 commandPayload.csChargingProfiles
581 );
582 logger.debug(
08f130a0 583 `${chargingStation.logPrefix()} Charging profile(s) set on connector id ${
ad8537a7 584 commandPayload.connectorId
ad67a158
JB
585 }: %j`,
586 commandPayload.csChargingProfiles
e7aeea18 587 );
bf53cadf 588 return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
c0560973
JB
589 }
590
41189456
JB
591 private handleRequestGetCompositeSchedule(
592 chargingStation: ChargingStation,
593 commandPayload: OCPP16GetCompositeScheduleRequest
594 ): OCPP16GetCompositeScheduleResponse {
595 if (
596 OCPP16ServiceUtils.checkFeatureProfile(
597 chargingStation,
598 OCPP16SupportedFeatureProfiles.SmartCharging,
599 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE
600 ) === false
601 ) {
602 return OCPPConstants.OCPP_RESPONSE_REJECTED;
603 }
604 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
605 logger.error(
606 `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector Id ${
607 commandPayload.connectorId
608 }`
609 );
610 return OCPPConstants.OCPP_RESPONSE_REJECTED;
611 }
612 if (
613 Utils.isEmptyArray(
614 chargingStation.getConnectorStatus(commandPayload.connectorId)?.chargingProfiles
615 )
616 ) {
617 return OCPPConstants.OCPP_RESPONSE_REJECTED;
618 }
619 const startDate = new Date();
620 const endDate = new Date(startDate.getTime() + commandPayload.duration * 1000);
621 let compositeSchedule: OCPP16ChargingSchedule;
622 for (const chargingProfile of chargingStation.getConnectorStatus(commandPayload.connectorId)
623 .chargingProfiles) {
624 // FIXME: build the composite schedule including the local power limit, the stack level, the charging rate unit, etc.
625 if (
626 chargingProfile.chargingSchedule?.startSchedule >= startDate &&
627 chargingProfile.chargingSchedule?.startSchedule <= endDate
628 ) {
629 compositeSchedule = chargingProfile.chargingSchedule;
630 break;
631 }
632 }
633 return {
634 status: GenericStatus.Accepted,
635 scheduleStart: compositeSchedule?.startSchedule,
636 connectorId: commandPayload.connectorId,
637 chargingSchedule: compositeSchedule,
638 };
639 }
640
e7aeea18 641 private handleRequestClearChargingProfile(
08f130a0 642 chargingStation: ChargingStation,
e7aeea18
JB
643 commandPayload: ClearChargingProfileRequest
644 ): ClearChargingProfileResponse {
370ae4ee 645 if (
a36bad10 646 OCPP16ServiceUtils.checkFeatureProfile(
08f130a0 647 chargingStation,
370ae4ee
JB
648 OCPP16SupportedFeatureProfiles.SmartCharging,
649 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE
a36bad10 650 ) === false
370ae4ee 651 ) {
bf53cadf 652 return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
68cb8b91 653 }
1789ba2c 654 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
e7aeea18 655 logger.error(
08f130a0 656 `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${
e7aeea18
JB
657 commandPayload.connectorId
658 }`
659 );
bf53cadf 660 return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
c0560973 661 }
1789ba2c 662 const connectorStatus = chargingStation.getConnectorStatus(commandPayload.connectorId);
d812bdcb
JB
663 if (
664 !Utils.isNullOrUndefined(commandPayload.connectorId) &&
53ac516c 665 Utils.isNotEmptyArray(connectorStatus?.chargingProfiles)
d812bdcb 666 ) {
658e2d16 667 connectorStatus.chargingProfiles = [];
e7aeea18 668 logger.debug(
08f130a0 669 `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
ad8537a7 670 commandPayload.connectorId
ad67a158 671 }`
e7aeea18 672 );
bf53cadf 673 return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
c0560973 674 }
d812bdcb 675 if (Utils.isNullOrUndefined(commandPayload.connectorId)) {
c0560973 676 let clearedCP = false;
08f130a0 677 for (const connectorId of chargingStation.connectors.keys()) {
72092cfc 678 if (
53ac516c 679 Utils.isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)
72092cfc 680 ) {
08f130a0 681 chargingStation
e7aeea18 682 .getConnectorStatus(connectorId)
72092cfc 683 ?.chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
e7aeea18
JB
684 let clearCurrentCP = false;
685 if (chargingProfile.chargingProfileId === commandPayload.id) {
686 clearCurrentCP = true;
687 }
688 if (
689 !commandPayload.chargingProfilePurpose &&
690 chargingProfile.stackLevel === commandPayload.stackLevel
691 ) {
692 clearCurrentCP = true;
693 }
694 if (
695 !chargingProfile.stackLevel &&
696 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
697 ) {
698 clearCurrentCP = true;
699 }
700 if (
701 chargingProfile.stackLevel === commandPayload.stackLevel &&
702 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
703 ) {
704 clearCurrentCP = true;
705 }
706 if (clearCurrentCP) {
72092cfc 707 connectorStatus?.chargingProfiles?.splice(index, 1);
e7aeea18 708 logger.debug(
ad67a158
JB
709 `${chargingStation.logPrefix()} Matching charging profile(s) cleared: %j`,
710 chargingProfile
e7aeea18
JB
711 );
712 clearedCP = true;
713 }
714 });
c0560973
JB
715 }
716 }
717 if (clearedCP) {
bf53cadf 718 return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
c0560973
JB
719 }
720 }
bf53cadf 721 return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
c0560973
JB
722 }
723
e7aeea18 724 private async handleRequestChangeAvailability(
08f130a0 725 chargingStation: ChargingStation,
e7aeea18
JB
726 commandPayload: ChangeAvailabilityRequest
727 ): Promise<ChangeAvailabilityResponse> {
c0560973 728 const connectorId: number = commandPayload.connectorId;
c60ed4b8 729 if (chargingStation.connectors.has(connectorId) === false) {
e7aeea18 730 logger.error(
08f130a0 731 `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`
e7aeea18 732 );
bf53cadf 733 return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
c0560973 734 }
e7aeea18
JB
735 const chargePointStatus: OCPP16ChargePointStatus =
736 commandPayload.type === OCPP16AvailabilityType.OPERATIVE
721646e9
JB
737 ? OCPP16ChargePointStatus.Available
738 : OCPP16ChargePointStatus.Unavailable;
c0560973 739 if (connectorId === 0) {
bf53cadf 740 let response: ChangeAvailabilityResponse = OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
08f130a0 741 for (const id of chargingStation.connectors.keys()) {
5e3cb728 742 if (chargingStation.getConnectorStatus(id)?.transactionStarted === true) {
bf53cadf 743 response = OCPPConstants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
c0560973 744 }
08f130a0 745 chargingStation.getConnectorStatus(id).availability = commandPayload.type;
bf53cadf 746 if (response === OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
08f130a0 747 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
748 OCPP16StatusNotificationRequest,
749 OCPP16StatusNotificationResponse
08f130a0 750 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb
JB
751 connectorId: id,
752 status: chargePointStatus,
753 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
754 });
08f130a0 755 chargingStation.getConnectorStatus(id).status = chargePointStatus;
c0560973
JB
756 }
757 }
758 return response;
e7aeea18
JB
759 } else if (
760 connectorId > 0 &&
56eb297e
JB
761 (chargingStation.isChargingStationAvailable() === true ||
762 (chargingStation.isChargingStationAvailable() === false &&
e7aeea18
JB
763 commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))
764 ) {
5e3cb728 765 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
08f130a0 766 chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
bf53cadf 767 return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
c0560973 768 }
08f130a0
JB
769 chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
770 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
771 OCPP16StatusNotificationRequest,
772 OCPP16StatusNotificationResponse
08f130a0 773 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb
JB
774 connectorId,
775 status: chargePointStatus,
776 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
777 });
08f130a0 778 chargingStation.getConnectorStatus(connectorId).status = chargePointStatus;
bf53cadf 779 return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
c0560973 780 }
bf53cadf 781 return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
c0560973
JB
782 }
783
e7aeea18 784 private async handleRequestRemoteStartTransaction(
08f130a0 785 chargingStation: ChargingStation,
e7aeea18 786 commandPayload: RemoteStartTransactionRequest
f03e1042 787 ): Promise<GenericResponse> {
658e2d16 788 const transactionConnectorId = commandPayload.connectorId;
1789ba2c 789 if (chargingStation.connectors.has(transactionConnectorId) === true) {
44eb6026
JB
790 const remoteStartTransactionLogMsg = `${chargingStation.logPrefix()} Transaction remotely STARTED on ${
791 chargingStation.stationInfo.chargingStationId
792 }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`;
08f130a0 793 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
794 OCPP16StatusNotificationRequest,
795 OCPP16StatusNotificationResponse
08f130a0 796 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 797 connectorId: transactionConnectorId,
721646e9 798 status: OCPP16ChargePointStatus.Preparing,
ef6fa3fb
JB
799 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
800 });
1789ba2c 801 const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId);
721646e9 802 connectorStatus.status = OCPP16ChargePointStatus.Preparing;
62340a29
JB
803 if (
804 chargingStation.isChargingStationAvailable() === true &&
805 chargingStation.isConnectorAvailable(transactionConnectorId) === true
806 ) {
e060fe58 807 // Check if authorized
1789ba2c 808 if (chargingStation.getAuthorizeRemoteTxRequests() === true) {
a7fc8211 809 let authorized = false;
e7aeea18 810 if (
1789ba2c 811 chargingStation.getLocalAuthListEnabled() === true &&
f911a4af 812 chargingStation.hasIdTags() === true &&
5a2a53cf 813 Utils.isNotEmptyString(
f911a4af 814 chargingStation.idTagsCache
e302df1d 815 .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo))
d812bdcb
JB
816 ?.find((idTag) => idTag === commandPayload.idTag)
817 )
e7aeea18 818 ) {
658e2d16
JB
819 connectorStatus.localAuthorizeIdTag = commandPayload.idTag;
820 connectorStatus.idTagLocalAuthorized = true;
36f6a92e 821 authorized = true;
1789ba2c 822 } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
658e2d16 823 connectorStatus.authorizeIdTag = commandPayload.idTag;
2e3d65ae 824 const authorizeResponse: OCPP16AuthorizeResponse =
08f130a0 825 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
826 OCPP16AuthorizeRequest,
827 OCPP16AuthorizeResponse
08f130a0 828 >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
ef6fa3fb
JB
829 idTag: commandPayload.idTag,
830 });
a7fc8211
JB
831 if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
832 authorized = true;
a7fc8211 833 }
71068fb9 834 } else {
e7aeea18 835 logger.warn(
08f130a0 836 `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
e7aeea18 837 );
a7fc8211 838 }
1789ba2c 839 if (authorized === true) {
a7fc8211 840 // Authorization successful, start transaction
e7aeea18
JB
841 if (
842 this.setRemoteStartTransactionChargingProfile(
08f130a0 843 chargingStation,
e7aeea18
JB
844 transactionConnectorId,
845 commandPayload.chargingProfile
1789ba2c 846 ) === true
e7aeea18 847 ) {
658e2d16 848 connectorStatus.transactionRemoteStarted = true;
e7aeea18
JB
849 if (
850 (
08f130a0 851 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
852 OCPP16StartTransactionRequest,
853 OCPP16StartTransactionResponse
08f130a0 854 >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
ef6fa3fb
JB
855 connectorId: transactionConnectorId,
856 idTag: commandPayload.idTag,
857 })
e7aeea18
JB
858 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
859 ) {
91a4f151 860 logger.debug(remoteStartTransactionLogMsg);
bf53cadf 861 return OCPPConstants.OCPP_RESPONSE_ACCEPTED;
e060fe58 862 }
e7aeea18 863 return this.notifyRemoteStartTransactionRejected(
08f130a0 864 chargingStation,
e7aeea18
JB
865 transactionConnectorId,
866 commandPayload.idTag
867 );
e060fe58 868 }
e7aeea18 869 return this.notifyRemoteStartTransactionRejected(
08f130a0 870 chargingStation,
e7aeea18
JB
871 transactionConnectorId,
872 commandPayload.idTag
873 );
a7fc8211 874 }
e7aeea18 875 return this.notifyRemoteStartTransactionRejected(
08f130a0 876 chargingStation,
e7aeea18
JB
877 transactionConnectorId,
878 commandPayload.idTag
879 );
36f6a92e 880 }
a7fc8211 881 // No authorization check required, start transaction
e7aeea18
JB
882 if (
883 this.setRemoteStartTransactionChargingProfile(
08f130a0 884 chargingStation,
e7aeea18
JB
885 transactionConnectorId,
886 commandPayload.chargingProfile
1789ba2c 887 ) === true
e7aeea18 888 ) {
658e2d16 889 connectorStatus.transactionRemoteStarted = true;
e7aeea18
JB
890 if (
891 (
08f130a0 892 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
893 OCPP16StartTransactionRequest,
894 OCPP16StartTransactionResponse
08f130a0 895 >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
ef6fa3fb
JB
896 connectorId: transactionConnectorId,
897 idTag: commandPayload.idTag,
898 })
e7aeea18
JB
899 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
900 ) {
91a4f151 901 logger.debug(remoteStartTransactionLogMsg);
bf53cadf 902 return OCPPConstants.OCPP_RESPONSE_ACCEPTED;
e060fe58 903 }
e7aeea18 904 return this.notifyRemoteStartTransactionRejected(
08f130a0 905 chargingStation,
e7aeea18
JB
906 transactionConnectorId,
907 commandPayload.idTag
908 );
e060fe58 909 }
e7aeea18 910 return this.notifyRemoteStartTransactionRejected(
08f130a0 911 chargingStation,
e7aeea18
JB
912 transactionConnectorId,
913 commandPayload.idTag
914 );
c0560973 915 }
e7aeea18 916 return this.notifyRemoteStartTransactionRejected(
08f130a0 917 chargingStation,
e7aeea18
JB
918 transactionConnectorId,
919 commandPayload.idTag
920 );
c0560973 921 }
08f130a0
JB
922 return this.notifyRemoteStartTransactionRejected(
923 chargingStation,
924 transactionConnectorId,
925 commandPayload.idTag
926 );
a7fc8211
JB
927 }
928
e7aeea18 929 private async notifyRemoteStartTransactionRejected(
08f130a0 930 chargingStation: ChargingStation,
e7aeea18
JB
931 connectorId: number,
932 idTag: string
f03e1042 933 ): Promise<GenericResponse> {
e7aeea18 934 if (
721646e9 935 chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Available
e7aeea18 936 ) {
08f130a0 937 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
938 OCPP16StatusNotificationRequest,
939 OCPP16StatusNotificationResponse
08f130a0 940 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 941 connectorId,
721646e9 942 status: OCPP16ChargePointStatus.Available,
ef6fa3fb
JB
943 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
944 });
721646e9 945 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Available;
e060fe58 946 }
e7aeea18 947 logger.warn(
44eb6026 948 `${chargingStation.logPrefix()} Remote starting transaction REJECTED on connector Id ${connectorId.toString()}, idTag '${idTag}', availability '${
72092cfc
JB
949 chargingStation.getConnectorStatus(connectorId)?.availability
950 }', status '${chargingStation.getConnectorStatus(connectorId)?.status}'`
e7aeea18 951 );
bf53cadf 952 return OCPPConstants.OCPP_RESPONSE_REJECTED;
c0560973
JB
953 }
954
e7aeea18 955 private setRemoteStartTransactionChargingProfile(
08f130a0 956 chargingStation: ChargingStation,
e7aeea18
JB
957 connectorId: number,
958 cp: OCPP16ChargingProfile
959 ): boolean {
0ac97927 960 if (cp && cp.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.TX_PROFILE) {
ed3d2808 961 OCPP16ServiceUtils.setChargingProfile(chargingStation, connectorId, cp);
e7aeea18 962 logger.debug(
ad67a158
JB
963 `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}: %j`,
964 cp
e7aeea18 965 );
a7fc8211 966 return true;
0ac97927 967 } else if (cp && cp.chargingProfilePurpose !== OCPP16ChargingProfilePurposeType.TX_PROFILE) {
e7aeea18 968 logger.warn(
08f130a0 969 `${chargingStation.logPrefix()} Not allowed to set ${
e7aeea18
JB
970 cp.chargingProfilePurpose
971 } charging profile(s) at remote start transaction`
972 );
a7fc8211 973 return false;
e060fe58
JB
974 } else if (!cp) {
975 return true;
a7fc8211
JB
976 }
977 }
978
e7aeea18 979 private async handleRequestRemoteStopTransaction(
08f130a0 980 chargingStation: ChargingStation,
e7aeea18 981 commandPayload: RemoteStopTransactionRequest
f03e1042 982 ): Promise<GenericResponse> {
c0560973 983 const transactionId = commandPayload.transactionId;
08f130a0 984 for (const connectorId of chargingStation.connectors.keys()) {
e7aeea18
JB
985 if (
986 connectorId > 0 &&
08f130a0 987 chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
e7aeea18 988 ) {
08f130a0 989 await chargingStation.ocppRequestService.requestHandler<
ef6fa3fb
JB
990 OCPP16StatusNotificationRequest,
991 OCPP16StatusNotificationResponse
08f130a0 992 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
ef6fa3fb 993 connectorId,
721646e9 994 status: OCPP16ChargePointStatus.Finishing,
ef6fa3fb
JB
995 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
996 });
721646e9 997 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Finishing;
5e3cb728
JB
998 const stopResponse = await chargingStation.stopTransactionOnConnector(
999 connectorId,
a65319ba 1000 OCPP16StopTransactionReason.REMOTE
5e3cb728
JB
1001 );
1002 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
bf53cadf 1003 return OCPPConstants.OCPP_RESPONSE_ACCEPTED;
ef6fa3fb 1004 }
bf53cadf 1005 return OCPPConstants.OCPP_RESPONSE_REJECTED;
c0560973
JB
1006 }
1007 }
44b9b577 1008 logger.warn(
44eb6026 1009 `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction ${transactionId.toString()}`
e7aeea18 1010 );
bf53cadf 1011 return OCPPConstants.OCPP_RESPONSE_REJECTED;
c0560973 1012 }
47e22477 1013
b03df580
JB
1014 private handleRequestUpdateFirmware(
1015 chargingStation: ChargingStation,
1016 commandPayload: OCPP16UpdateFirmwareRequest
1017 ): OCPP16UpdateFirmwareResponse {
1018 if (
1019 OCPP16ServiceUtils.checkFeatureProfile(
1020 chargingStation,
1021 OCPP16SupportedFeatureProfiles.FirmwareManagement,
1022 OCPP16IncomingRequestCommand.UPDATE_FIRMWARE
1023 ) === false
1024 ) {
5d280aae 1025 logger.warn(
90293abb 1026 `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: feature profile not supported`
5d280aae
JB
1027 );
1028 return OCPPConstants.OCPP_RESPONSE_EMPTY;
1029 }
1030 if (
1031 !Utils.isNullOrUndefined(chargingStation.stationInfo.firmwareStatus) &&
1032 chargingStation.stationInfo.firmwareStatus !== OCPP16FirmwareStatus.Installed
1033 ) {
1034 logger.warn(
90293abb 1035 `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: firmware update is already in progress`
5d280aae 1036 );
bf53cadf 1037 return OCPPConstants.OCPP_RESPONSE_EMPTY;
b03df580 1038 }
c9a4f9ea 1039 const retrieveDate = Utils.convertToDate(commandPayload.retrieveDate);
2c7bdc61 1040 const now = Date.now();
72092cfc 1041 if (retrieveDate?.getTime() <= now) {
27f08ad3 1042 this.runInAsyncScope(
62340a29 1043 this.updateFirmwareSimulation.bind(this) as (
27f08ad3
JB
1044 this: OCPP16IncomingRequestService,
1045 ...args: any[]
1046 ) => Promise<void>,
1047 this,
1048 chargingStation
59b6ed8d 1049 ).catch(Constants.EMPTY_FUNCTION);
c9a4f9ea
JB
1050 } else {
1051 setTimeout(() => {
62340a29 1052 this.updateFirmwareSimulation(chargingStation).catch(Constants.EMPTY_FUNCTION);
72092cfc 1053 }, retrieveDate?.getTime() - now);
c9a4f9ea
JB
1054 }
1055 return OCPPConstants.OCPP_RESPONSE_EMPTY;
1056 }
1057
62340a29 1058 private async updateFirmwareSimulation(
c9a4f9ea 1059 chargingStation: ChargingStation,
90293abb
JB
1060 maxDelay = 30,
1061 minDelay = 15
c9a4f9ea 1062 ): Promise<void> {
1bf29f5b
JB
1063 if (
1064 ChargingStationUtils.checkChargingStation(chargingStation, chargingStation.logPrefix()) ===
1065 false
1066 ) {
1067 return;
1068 }
c9a4f9ea
JB
1069 for (const connectorId of chargingStation.connectors.keys()) {
1070 if (
1071 connectorId > 0 &&
72092cfc 1072 chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false
c9a4f9ea
JB
1073 ) {
1074 await chargingStation.ocppRequestService.requestHandler<
1075 OCPP16StatusNotificationRequest,
1076 OCPP16StatusNotificationResponse
1077 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
1078 connectorId,
721646e9 1079 status: OCPP16ChargePointStatus.Unavailable,
c9a4f9ea
JB
1080 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1081 });
3637ca2c 1082 chargingStation.getConnectorStatus(connectorId).status =
721646e9 1083 OCPP16ChargePointStatus.Unavailable;
c9a4f9ea
JB
1084 }
1085 }
93f0c2c8
JB
1086 await chargingStation.ocppRequestService.requestHandler<
1087 OCPP16FirmwareStatusNotificationRequest,
1088 OCPP16FirmwareStatusNotificationResponse
1089 >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
1090 status: OCPP16FirmwareStatus.Downloading,
1091 });
1092 chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Downloading;
5d280aae 1093 if (
93f0c2c8
JB
1094 chargingStation.stationInfo?.firmwareUpgrade?.failureStatus ===
1095 OCPP16FirmwareStatus.DownloadFailed
5d280aae 1096 ) {
93f0c2c8 1097 await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000);
5d280aae
JB
1098 await chargingStation.ocppRequestService.requestHandler<
1099 OCPP16FirmwareStatusNotificationRequest,
1100 OCPP16FirmwareStatusNotificationResponse
1101 >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
15748260 1102 status: chargingStation.stationInfo?.firmwareUpgrade?.failureStatus,
5d280aae 1103 });
93f0c2c8
JB
1104 chargingStation.stationInfo.firmwareStatus =
1105 chargingStation.stationInfo?.firmwareUpgrade?.failureStatus;
5d280aae
JB
1106 return;
1107 }
90293abb 1108 await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000);
c9a4f9ea
JB
1109 await chargingStation.ocppRequestService.requestHandler<
1110 OCPP16FirmwareStatusNotificationRequest,
1111 OCPP16FirmwareStatusNotificationResponse
1112 >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
1113 status: OCPP16FirmwareStatus.Downloaded,
1114 });
1115 chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Downloaded;
380ccc42 1116 let wasTransactionsStarted = false;
62340a29
JB
1117 let transactionsStarted: boolean;
1118 do {
1119 let trxCount = 0;
1120 for (const connectorId of chargingStation.connectors.keys()) {
1121 if (
1122 connectorId > 0 &&
1123 chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true
1124 ) {
1125 trxCount++;
1126 }
1127 }
1128 if (trxCount > 0) {
1129 const waitTime = 15 * 1000;
1130 logger.debug(
1131 `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${trxCount} transaction(s) in progress, waiting ${
1132 waitTime / 1000
1133 } seconds before continuing firmware update simulation`
1134 );
1135 await Utils.sleep(waitTime);
1136 transactionsStarted = true;
380ccc42 1137 wasTransactionsStarted = true;
62340a29
JB
1138 } else {
1139 for (const connectorId of chargingStation.connectors.keys()) {
1140 if (
1141 connectorId > 0 &&
1142 chargingStation.getConnectorStatus(connectorId)?.status !==
1143 OCPP16ChargePointStatus.Unavailable
1144 ) {
1145 await chargingStation.ocppRequestService.requestHandler<
1146 OCPP16StatusNotificationRequest,
1147 OCPP16StatusNotificationResponse
1148 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
1149 connectorId,
1150 status: OCPP16ChargePointStatus.Unavailable,
1151 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1152 });
1153 chargingStation.getConnectorStatus(connectorId).status =
1154 OCPP16ChargePointStatus.Unavailable;
1155 }
1156 }
1157 transactionsStarted = false;
1158 }
1159 } while (transactionsStarted);
380ccc42
JB
1160 !wasTransactionsStarted &&
1161 (await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000));
1bf29f5b
JB
1162 if (
1163 ChargingStationUtils.checkChargingStation(chargingStation, chargingStation.logPrefix()) ===
1164 false
1165 ) {
1166 return;
1167 }
c9a4f9ea
JB
1168 await chargingStation.ocppRequestService.requestHandler<
1169 OCPP16FirmwareStatusNotificationRequest,
1170 OCPP16FirmwareStatusNotificationResponse
1171 >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
1172 status: OCPP16FirmwareStatus.Installing,
1173 });
1174 chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Installing;
93f0c2c8
JB
1175 if (
1176 chargingStation.stationInfo?.firmwareUpgrade?.failureStatus ===
1177 OCPP16FirmwareStatus.InstallationFailed
1178 ) {
1179 await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000);
1180 await chargingStation.ocppRequestService.requestHandler<
1181 OCPP16FirmwareStatusNotificationRequest,
1182 OCPP16FirmwareStatusNotificationResponse
1183 >(chargingStation, OCPP16RequestCommand.FIRMWARE_STATUS_NOTIFICATION, {
1184 status: chargingStation.stationInfo?.firmwareUpgrade?.failureStatus,
1185 });
1186 chargingStation.stationInfo.firmwareStatus =
1187 chargingStation.stationInfo?.firmwareUpgrade?.failureStatus;
1188 return;
1189 }
15748260 1190 if (chargingStation.stationInfo?.firmwareUpgrade?.reset === true) {
90293abb 1191 await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000);
5d280aae
JB
1192 await chargingStation.reset(OCPP16StopTransactionReason.REBOOT);
1193 }
b03df580
JB
1194 }
1195
e7aeea18 1196 private async handleRequestGetDiagnostics(
08f130a0 1197 chargingStation: ChargingStation,
e7aeea18
JB
1198 commandPayload: GetDiagnosticsRequest
1199 ): Promise<GetDiagnosticsResponse> {
68cb8b91 1200 if (
1789ba2c 1201 OCPP16ServiceUtils.checkFeatureProfile(
08f130a0 1202 chargingStation,
370ae4ee
JB
1203 OCPP16SupportedFeatureProfiles.FirmwareManagement,
1204 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1789ba2c 1205 ) === false
68cb8b91 1206 ) {
90293abb
JB
1207 logger.warn(
1208 `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Cannot get diagnostics: feature profile not supported`
1209 );
bf53cadf 1210 return OCPPConstants.OCPP_RESPONSE_EMPTY;
68cb8b91 1211 }
a3868ec4 1212 const uri = new URL(commandPayload.location);
47e22477
JB
1213 if (uri.protocol.startsWith('ftp:')) {
1214 let ftpClient: Client;
1215 try {
e7aeea18 1216 const logFiles = fs
0d8140bd 1217 .readdirSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'))
72092cfc
JB
1218 .filter((file) => file.endsWith('.log'))
1219 .map((file) => path.join('./', file));
44eb6026 1220 const diagnosticsArchive = `${chargingStation.stationInfo.chargingStationId}_logs.tar.gz`;
47e22477
JB
1221 tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
1222 ftpClient = new Client();
1223 const accessResponse = await ftpClient.access({
1224 host: uri.host,
5a2a53cf
JB
1225 ...(Utils.isNotEmptyString(uri.port) && { port: Utils.convertToInt(uri.port) }),
1226 ...(Utils.isNotEmptyString(uri.username) && { user: uri.username }),
1227 ...(Utils.isNotEmptyString(uri.password) && { password: uri.password }),
47e22477
JB
1228 });
1229 let uploadResponse: FTPResponse;
1230 if (accessResponse.code === 220) {
72092cfc 1231 ftpClient.trackProgress((info) => {
e7aeea18 1232 logger.info(
08f130a0 1233 `${chargingStation.logPrefix()} ${
e7aeea18
JB
1234 info.bytes / 1024
1235 } bytes transferred from diagnostics archive ${info.name}`
1236 );
6a8329b4
JB
1237 chargingStation.ocppRequestService
1238 .requestHandler<
1239 OCPP16DiagnosticsStatusNotificationRequest,
1240 OCPP16DiagnosticsStatusNotificationResponse
1241 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1242 status: OCPP16DiagnosticsStatus.Uploading,
1243 })
72092cfc 1244 .catch((error) => {
6a8329b4
JB
1245 logger.error(
1246 `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Error while sending '${
1247 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION
1248 }'`,
1249 error
1250 );
1251 });
47e22477 1252 });
e7aeea18 1253 uploadResponse = await ftpClient.uploadFrom(
0d8140bd
JB
1254 path.join(
1255 path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'),
1256 diagnosticsArchive
1257 ),
14ecae6a 1258 `${uri.pathname}${diagnosticsArchive}`
e7aeea18 1259 );
47e22477 1260 if (uploadResponse.code === 226) {
08f130a0 1261 await chargingStation.ocppRequestService.requestHandler<
c9a4f9ea
JB
1262 OCPP16DiagnosticsStatusNotificationRequest,
1263 OCPP16DiagnosticsStatusNotificationResponse
08f130a0 1264 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
ef6fa3fb
JB
1265 status: OCPP16DiagnosticsStatus.Uploaded,
1266 });
47e22477
JB
1267 if (ftpClient) {
1268 ftpClient.close();
1269 }
1270 return { fileName: diagnosticsArchive };
1271 }
e7aeea18
JB
1272 throw new OCPPError(
1273 ErrorType.GENERIC_ERROR,
1274 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
44eb6026 1275 uploadResponse?.code && `|${uploadResponse?.code.toString()}`
e7aeea18
JB
1276 }`,
1277 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1278 );
47e22477 1279 }
e7aeea18
JB
1280 throw new OCPPError(
1281 ErrorType.GENERIC_ERROR,
1282 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
44eb6026 1283 uploadResponse?.code && `|${uploadResponse?.code.toString()}`
e7aeea18
JB
1284 }`,
1285 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1286 );
47e22477 1287 } catch (error) {
08f130a0 1288 await chargingStation.ocppRequestService.requestHandler<
c9a4f9ea
JB
1289 OCPP16DiagnosticsStatusNotificationRequest,
1290 OCPP16DiagnosticsStatusNotificationResponse
08f130a0 1291 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
ef6fa3fb
JB
1292 status: OCPP16DiagnosticsStatus.UploadFailed,
1293 });
47e22477
JB
1294 if (ftpClient) {
1295 ftpClient.close();
1296 }
e7aeea18 1297 return this.handleIncomingRequestError(
08f130a0 1298 chargingStation,
e7aeea18
JB
1299 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
1300 error as Error,
bf53cadf 1301 { errorResponse: OCPPConstants.OCPP_RESPONSE_EMPTY }
e7aeea18 1302 );
47e22477
JB
1303 }
1304 } else {
e7aeea18 1305 logger.error(
08f130a0 1306 `${chargingStation.logPrefix()} Unsupported protocol ${
e7aeea18
JB
1307 uri.protocol
1308 } to transfer the diagnostic logs archive`
1309 );
08f130a0 1310 await chargingStation.ocppRequestService.requestHandler<
c9a4f9ea
JB
1311 OCPP16DiagnosticsStatusNotificationRequest,
1312 OCPP16DiagnosticsStatusNotificationResponse
08f130a0 1313 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
ef6fa3fb
JB
1314 status: OCPP16DiagnosticsStatus.UploadFailed,
1315 });
bf53cadf 1316 return OCPPConstants.OCPP_RESPONSE_EMPTY;
47e22477
JB
1317 }
1318 }
802cfa13 1319
e7aeea18 1320 private handleRequestTriggerMessage(
08f130a0 1321 chargingStation: ChargingStation,
e7aeea18
JB
1322 commandPayload: OCPP16TriggerMessageRequest
1323 ): OCPP16TriggerMessageResponse {
370ae4ee
JB
1324 if (
1325 !OCPP16ServiceUtils.checkFeatureProfile(
08f130a0 1326 chargingStation,
370ae4ee
JB
1327 OCPP16SupportedFeatureProfiles.RemoteTrigger,
1328 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
c60ed4b8
JB
1329 ) ||
1330 !OCPP16ServiceUtils.isMessageTriggerSupported(
1331 chargingStation,
1332 commandPayload.requestedMessage
370ae4ee
JB
1333 )
1334 ) {
bf53cadf 1335 return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
68cb8b91 1336 }
c60ed4b8 1337 if (
4caa7e67 1338 !OCPP16ServiceUtils.isConnectorIdValid(
c60ed4b8
JB
1339 chargingStation,
1340 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
1341 commandPayload.connectorId
1342 )
1343 ) {
bf53cadf 1344 return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED;
dc661702 1345 }
802cfa13
JB
1346 try {
1347 switch (commandPayload.requestedMessage) {
c60ed4b8 1348 case OCPP16MessageTrigger.BootNotification:
802cfa13 1349 setTimeout(() => {
08f130a0 1350 chargingStation.ocppRequestService
f7f98c68 1351 .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
08f130a0 1352 chargingStation,
6a8b180d 1353 OCPP16RequestCommand.BOOT_NOTIFICATION,
8bfbc743 1354 chargingStation.bootNotificationRequest,
6a8b180d 1355 { skipBufferingOnError: true, triggerMessage: true }
e7aeea18 1356 )
72092cfc 1357 .then((response) => {
8bfbc743 1358 chargingStation.bootNotificationResponse = response;
ae711c83 1359 })
59b6ed8d 1360 .catch(Constants.EMPTY_FUNCTION);
802cfa13 1361 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
bf53cadf 1362 return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
c60ed4b8 1363 case OCPP16MessageTrigger.Heartbeat:
802cfa13 1364 setTimeout(() => {
08f130a0 1365 chargingStation.ocppRequestService
f7f98c68 1366 .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
08f130a0 1367 chargingStation,
ef6fa3fb
JB
1368 OCPP16RequestCommand.HEARTBEAT,
1369 null,
1370 {
1371 triggerMessage: true,
1372 }
1373 )
59b6ed8d 1374 .catch(Constants.EMPTY_FUNCTION);
802cfa13 1375 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
bf53cadf 1376 return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
c60ed4b8 1377 case OCPP16MessageTrigger.StatusNotification:
dc661702 1378 setTimeout(() => {
d812bdcb 1379 if (!Utils.isNullOrUndefined(commandPayload?.connectorId)) {
08f130a0 1380 chargingStation.ocppRequestService
dc661702 1381 .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
08f130a0 1382 chargingStation,
dc661702
JB
1383 OCPP16RequestCommand.STATUS_NOTIFICATION,
1384 {
1385 connectorId: commandPayload.connectorId,
1386 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
72092cfc 1387 status: chargingStation.getConnectorStatus(commandPayload.connectorId)?.status,
dc661702
JB
1388 },
1389 {
1390 triggerMessage: true,
1391 }
1392 )
59b6ed8d 1393 .catch(Constants.EMPTY_FUNCTION);
dc661702 1394 } else {
08f130a0
JB
1395 for (const connectorId of chargingStation.connectors.keys()) {
1396 chargingStation.ocppRequestService
dc661702
JB
1397 .requestHandler<
1398 OCPP16StatusNotificationRequest,
1399 OCPP16StatusNotificationResponse
1400 >(
08f130a0 1401 chargingStation,
dc661702
JB
1402 OCPP16RequestCommand.STATUS_NOTIFICATION,
1403 {
1404 connectorId,
1405 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
72092cfc 1406 status: chargingStation.getConnectorStatus(connectorId)?.status,
dc661702
JB
1407 },
1408 {
1409 triggerMessage: true,
1410 }
1411 )
59b6ed8d 1412 .catch(Constants.EMPTY_FUNCTION);
dc661702
JB
1413 }
1414 }
1415 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
bf53cadf 1416 return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
802cfa13 1417 default:
bf53cadf 1418 return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
802cfa13
JB
1419 }
1420 } catch (error) {
e7aeea18 1421 return this.handleIncomingRequestError(
08f130a0 1422 chargingStation,
e7aeea18
JB
1423 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
1424 error as Error,
bf53cadf 1425 { errorResponse: OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED }
e7aeea18 1426 );
802cfa13
JB
1427 }
1428 }
77b95a89
JB
1429
1430 private handleRequestDataTransfer(
1431 chargingStation: ChargingStation,
1432 commandPayload: OCPP16DataTransferRequest
1433 ): OCPP16DataTransferResponse {
1434 try {
1435 if (Object.values(OCPP16DataTransferVendorId).includes(commandPayload.vendorId)) {
1436 return {
1437 status: OCPP16DataTransferStatus.ACCEPTED,
1438 };
1439 }
1440 return {
1441 status: OCPP16DataTransferStatus.UNKNOWN_VENDOR_ID,
1442 };
1443 } catch (error) {
1444 return this.handleIncomingRequestError(
1445 chargingStation,
1446 OCPP16IncomingRequestCommand.DATA_TRANSFER,
1447 error as Error,
bf53cadf 1448 { errorResponse: OCPPConstants.OCPP_DATA_TRANSFER_RESPONSE_REJECTED }
77b95a89
JB
1449 );
1450 }
1451 }
c0560973 1452}