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