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