Fix connector Id validation in TriggerMessage handling
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16IncomingRequestService.ts
1 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
2
3 import fs from 'fs';
4 import path from 'path';
5 import { URL, fileURLToPath } from 'url';
6
7 import type { JSONSchemaType } from 'ajv';
8 import { Client, FTPResponse } from 'basic-ftp';
9 import tar from 'tar';
10
11 import OCPPError from '../../../exception/OCPPError';
12 import type { JsonObject, JsonType } from '../../../types/JsonType';
13 import { OCPP16ChargePointErrorCode } from '../../../types/ocpp/1.6/ChargePointErrorCode';
14 import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus';
15 import {
16 ChargingProfilePurposeType,
17 OCPP16ChargingProfile,
18 } from '../../../types/ocpp/1.6/ChargingProfile';
19 import {
20 OCPP16StandardParametersKey,
21 OCPP16SupportedFeatureProfiles,
22 } from '../../../types/ocpp/1.6/Configuration';
23 import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus';
24 import {
25 ChangeAvailabilityRequest,
26 ChangeConfigurationRequest,
27 ClearChargingProfileRequest,
28 DiagnosticsStatusNotificationRequest,
29 GetConfigurationRequest,
30 GetDiagnosticsRequest,
31 OCPP16AvailabilityType,
32 OCPP16BootNotificationRequest,
33 OCPP16ClearCacheRequest,
34 OCPP16HeartbeatRequest,
35 OCPP16IncomingRequestCommand,
36 OCPP16MessageTrigger,
37 OCPP16RequestCommand,
38 OCPP16StatusNotificationRequest,
39 OCPP16TriggerMessageRequest,
40 RemoteStartTransactionRequest,
41 RemoteStopTransactionRequest,
42 ResetRequest,
43 SetChargingProfileRequest,
44 UnlockConnectorRequest,
45 } from '../../../types/ocpp/1.6/Requests';
46 import type {
47 ChangeAvailabilityResponse,
48 ChangeConfigurationResponse,
49 ClearChargingProfileResponse,
50 DiagnosticsStatusNotificationResponse,
51 GetConfigurationResponse,
52 GetDiagnosticsResponse,
53 OCPP16BootNotificationResponse,
54 OCPP16HeartbeatResponse,
55 OCPP16StatusNotificationResponse,
56 OCPP16TriggerMessageResponse,
57 SetChargingProfileResponse,
58 UnlockConnectorResponse,
59 } from '../../../types/ocpp/1.6/Responses';
60 import {
61 OCPP16AuthorizationStatus,
62 OCPP16AuthorizeRequest,
63 OCPP16AuthorizeResponse,
64 OCPP16StartTransactionRequest,
65 OCPP16StartTransactionResponse,
66 OCPP16StopTransactionReason,
67 } from '../../../types/ocpp/1.6/Transaction';
68 import type { OCPPConfigurationKey } from '../../../types/ocpp/Configuration';
69 import { ErrorType } from '../../../types/ocpp/ErrorType';
70 import type { IncomingRequestHandler } from '../../../types/ocpp/Requests';
71 import type { DefaultResponse } from '../../../types/ocpp/Responses';
72 import Constants from '../../../utils/Constants';
73 import logger from '../../../utils/Logger';
74 import Utils from '../../../utils/Utils';
75 import type ChargingStation from '../../ChargingStation';
76 import { ChargingStationConfigurationUtils } from '../../ChargingStationConfigurationUtils';
77 import { ChargingStationUtils } from '../../ChargingStationUtils';
78 import OCPPIncomingRequestService from '../OCPPIncomingRequestService';
79 import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
80
81 const moduleName = 'OCPP16IncomingRequestService';
82
83 export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService {
84 private incomingRequestHandlers: Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>;
85 private jsonSchemas: Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>;
86
87 public constructor() {
88 if (new.target?.name === moduleName) {
89 throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
90 }
91 super();
92 this.incomingRequestHandlers = new Map<OCPP16IncomingRequestCommand, IncomingRequestHandler>([
93 [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
94 [OCPP16IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)],
95 [OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR, this.handleRequestUnlockConnector.bind(this)],
96 [
97 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
98 this.handleRequestGetConfiguration.bind(this),
99 ],
100 [
101 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
102 this.handleRequestChangeConfiguration.bind(this),
103 ],
104 [
105 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
106 this.handleRequestSetChargingProfile.bind(this),
107 ],
108 [
109 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
110 this.handleRequestClearChargingProfile.bind(this),
111 ],
112 [
113 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
114 this.handleRequestChangeAvailability.bind(this),
115 ],
116 [
117 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
118 this.handleRequestRemoteStartTransaction.bind(this),
119 ],
120 [
121 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
122 this.handleRequestRemoteStopTransaction.bind(this),
123 ],
124 [OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, this.handleRequestGetDiagnostics.bind(this)],
125 [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)],
126 ]);
127 this.jsonSchemas = new Map<OCPP16IncomingRequestCommand, JSONSchemaType<JsonObject>>([
128 [
129 OCPP16IncomingRequestCommand.RESET,
130 JSON.parse(
131 fs.readFileSync(
132 path.resolve(
133 path.dirname(fileURLToPath(import.meta.url)),
134 '../../../assets/json-schemas/ocpp/1.6/Reset.json'
135 ),
136 'utf8'
137 )
138 ) as JSONSchemaType<ResetRequest>,
139 ],
140 [
141 OCPP16IncomingRequestCommand.CLEAR_CACHE,
142 JSON.parse(
143 fs.readFileSync(
144 path.resolve(
145 path.dirname(fileURLToPath(import.meta.url)),
146 '../../../assets/json-schemas/ocpp/1.6/ClearCache.json'
147 ),
148 'utf8'
149 )
150 ) as JSONSchemaType<OCPP16ClearCacheRequest>,
151 ],
152 [
153 OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR,
154 JSON.parse(
155 fs.readFileSync(
156 path.resolve(
157 path.dirname(fileURLToPath(import.meta.url)),
158 '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json'
159 ),
160 'utf8'
161 )
162 ) as JSONSchemaType<UnlockConnectorRequest>,
163 ],
164 [
165 OCPP16IncomingRequestCommand.GET_CONFIGURATION,
166 JSON.parse(
167 fs.readFileSync(
168 path.resolve(
169 path.dirname(fileURLToPath(import.meta.url)),
170 '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json'
171 ),
172 'utf8'
173 )
174 ) as JSONSchemaType<GetConfigurationRequest>,
175 ],
176 [
177 OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
178 JSON.parse(
179 fs.readFileSync(
180 path.resolve(
181 path.dirname(fileURLToPath(import.meta.url)),
182 '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json'
183 ),
184 'utf8'
185 )
186 ) as JSONSchemaType<ChangeConfigurationRequest>,
187 ],
188 [
189 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
190 JSON.parse(
191 fs.readFileSync(
192 path.resolve(
193 path.dirname(fileURLToPath(import.meta.url)),
194 '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json'
195 ),
196 'utf8'
197 )
198 ) as JSONSchemaType<GetDiagnosticsRequest>,
199 ],
200 [
201 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
202 JSON.parse(
203 fs.readFileSync(
204 path.resolve(
205 path.dirname(fileURLToPath(import.meta.url)),
206 '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json'
207 ),
208 'utf8'
209 )
210 ) as JSONSchemaType<SetChargingProfileRequest>,
211 ],
212 [
213 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
214 JSON.parse(
215 fs.readFileSync(
216 path.resolve(
217 path.dirname(fileURLToPath(import.meta.url)),
218 '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json'
219 ),
220 'utf8'
221 )
222 ) as JSONSchemaType<ClearChargingProfileRequest>,
223 ],
224 [
225 OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
226 JSON.parse(
227 fs.readFileSync(
228 path.resolve(
229 path.dirname(fileURLToPath(import.meta.url)),
230 '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json'
231 ),
232 'utf8'
233 )
234 ) as JSONSchemaType<ChangeAvailabilityRequest>,
235 ],
236 [
237 OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
238 JSON.parse(
239 fs.readFileSync(
240 path.resolve(
241 path.dirname(fileURLToPath(import.meta.url)),
242 '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json'
243 ),
244 'utf8'
245 )
246 ) as JSONSchemaType<RemoteStartTransactionRequest>,
247 ],
248 [
249 OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
250 JSON.parse(
251 fs.readFileSync(
252 path.resolve(
253 path.dirname(fileURLToPath(import.meta.url)),
254 '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json'
255 ),
256 'utf8'
257 )
258 ) as JSONSchemaType<RemoteStopTransactionRequest>,
259 ],
260 [
261 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
262 JSON.parse(
263 fs.readFileSync(
264 path.resolve(
265 path.dirname(fileURLToPath(import.meta.url)),
266 '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json'
267 ),
268 'utf8'
269 )
270 ) as JSONSchemaType<OCPP16TriggerMessageRequest>,
271 ],
272 ]);
273 this.validatePayload.bind(this);
274 }
275
276 public async incomingRequestHandler(
277 chargingStation: ChargingStation,
278 messageId: string,
279 commandName: OCPP16IncomingRequestCommand,
280 commandPayload: JsonType
281 ): Promise<void> {
282 let response: JsonType;
283 if (
284 chargingStation.getOcppStrictCompliance() === true &&
285 chargingStation.isInPendingState() === true &&
286 (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION ||
287 commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)
288 ) {
289 throw new OCPPError(
290 ErrorType.SECURITY_ERROR,
291 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
292 commandPayload,
293 null,
294 2
295 )} while the charging station is in pending state on the central server`,
296 commandName,
297 commandPayload
298 );
299 }
300 if (
301 chargingStation.isRegistered() === true ||
302 (chargingStation.getOcppStrictCompliance() === false &&
303 chargingStation.isInUnknownState() === true)
304 ) {
305 if (
306 this.incomingRequestHandlers.has(commandName) === true &&
307 OCPP16ServiceUtils.isIncomingRequestCommandSupported(chargingStation, commandName) === true
308 ) {
309 try {
310 this.validatePayload(chargingStation, commandName, commandPayload);
311 // Call the method to build the response
312 response = await this.incomingRequestHandlers.get(commandName)(
313 chargingStation,
314 commandPayload
315 );
316 } catch (error) {
317 // Log
318 logger.error(
319 `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
320 error
321 );
322 throw error;
323 }
324 } else {
325 // Throw exception
326 throw new OCPPError(
327 ErrorType.NOT_IMPLEMENTED,
328 `${commandName} is not implemented to handle request PDU ${JSON.stringify(
329 commandPayload,
330 null,
331 2
332 )}`,
333 commandName,
334 commandPayload
335 );
336 }
337 } else {
338 throw new OCPPError(
339 ErrorType.SECURITY_ERROR,
340 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
341 commandPayload,
342 null,
343 2
344 )} while the charging station is not registered on the central server.`,
345 commandName,
346 commandPayload
347 );
348 }
349 // Send the built response
350 await chargingStation.ocppRequestService.sendResponse(
351 chargingStation,
352 messageId,
353 response,
354 commandName
355 );
356 }
357
358 private validatePayload(
359 chargingStation: ChargingStation,
360 commandName: OCPP16IncomingRequestCommand,
361 commandPayload: JsonType
362 ): boolean {
363 if (this.jsonSchemas.has(commandName)) {
364 return this.validateIncomingRequestPayload(
365 chargingStation,
366 commandName,
367 this.jsonSchemas.get(commandName),
368 commandPayload
369 );
370 }
371 logger.warn(
372 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command ${commandName} PDU validation`
373 );
374 return false;
375 }
376
377 // Simulate charging station restart
378 private handleRequestReset(
379 chargingStation: ChargingStation,
380 commandPayload: ResetRequest
381 ): DefaultResponse {
382 this.asyncResource
383 .runInAsyncScope(
384 chargingStation.reset.bind(chargingStation) as (
385 this: ChargingStation,
386 ...args: any[]
387 ) => Promise<void>,
388 chargingStation,
389 (commandPayload.type + 'Reset') as OCPP16StopTransactionReason
390 )
391 .catch(() => {
392 /* This is intentional */
393 });
394 logger.info(
395 `${chargingStation.logPrefix()} ${
396 commandPayload.type
397 } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
398 chargingStation.stationInfo.resetTime
399 )}`
400 );
401 return Constants.OCPP_RESPONSE_ACCEPTED;
402 }
403
404 private handleRequestClearCache(chargingStation: ChargingStation): DefaultResponse {
405 chargingStation.authorizedTagsCache.deleteAuthorizedTags(
406 ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo)
407 );
408 return Constants.OCPP_RESPONSE_ACCEPTED;
409 }
410
411 private async handleRequestUnlockConnector(
412 chargingStation: ChargingStation,
413 commandPayload: UnlockConnectorRequest
414 ): Promise<UnlockConnectorResponse> {
415 const connectorId = commandPayload.connectorId;
416 if (chargingStation.connectors.has(connectorId) === false) {
417 logger.error(
418 `${chargingStation.logPrefix()} Trying to unlock a non existing connector Id ${connectorId.toString()}`
419 );
420 return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
421 }
422 if (connectorId === 0) {
423 logger.error(
424 chargingStation.logPrefix() + ' Trying to unlock connector Id ' + connectorId.toString()
425 );
426 return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
427 }
428 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
429 const stopResponse = await chargingStation.stopTransactionOnConnector(
430 connectorId,
431 OCPP16StopTransactionReason.UNLOCK_COMMAND
432 );
433 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
434 return Constants.OCPP_RESPONSE_UNLOCKED;
435 }
436 return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
437 }
438 await chargingStation.ocppRequestService.requestHandler<
439 OCPP16StatusNotificationRequest,
440 OCPP16StatusNotificationResponse
441 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
442 connectorId,
443 status: OCPP16ChargePointStatus.AVAILABLE,
444 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
445 });
446 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
447 return Constants.OCPP_RESPONSE_UNLOCKED;
448 }
449
450 private handleRequestGetConfiguration(
451 chargingStation: ChargingStation,
452 commandPayload: GetConfigurationRequest
453 ): GetConfigurationResponse {
454 const configurationKey: OCPPConfigurationKey[] = [];
455 const unknownKey: string[] = [];
456 if (Utils.isEmptyArray(commandPayload.key) === true) {
457 for (const configuration of chargingStation.ocppConfiguration.configurationKey) {
458 if (Utils.isUndefined(configuration.visible) === true) {
459 configuration.visible = true;
460 }
461 if (configuration.visible === false) {
462 continue;
463 }
464 configurationKey.push({
465 key: configuration.key,
466 readonly: configuration.readonly,
467 value: configuration.value,
468 });
469 }
470 } else {
471 for (const key of commandPayload.key) {
472 const keyFound = ChargingStationConfigurationUtils.getConfigurationKey(
473 chargingStation,
474 key
475 );
476 if (keyFound) {
477 if (Utils.isUndefined(keyFound.visible) === true) {
478 keyFound.visible = true;
479 }
480 if (keyFound.visible === false) {
481 continue;
482 }
483 configurationKey.push({
484 key: keyFound.key,
485 readonly: keyFound.readonly,
486 value: keyFound.value,
487 });
488 } else {
489 unknownKey.push(key);
490 }
491 }
492 }
493 return {
494 configurationKey,
495 unknownKey,
496 };
497 }
498
499 private handleRequestChangeConfiguration(
500 chargingStation: ChargingStation,
501 commandPayload: ChangeConfigurationRequest
502 ): ChangeConfigurationResponse {
503 const keyToChange = ChargingStationConfigurationUtils.getConfigurationKey(
504 chargingStation,
505 commandPayload.key,
506 true
507 );
508 if (!keyToChange) {
509 return Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
510 } else if (keyToChange && keyToChange.readonly) {
511 return Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
512 } else if (keyToChange && !keyToChange.readonly) {
513 let valueChanged = false;
514 if (keyToChange.value !== commandPayload.value) {
515 ChargingStationConfigurationUtils.setConfigurationKeyValue(
516 chargingStation,
517 commandPayload.key,
518 commandPayload.value,
519 true
520 );
521 valueChanged = true;
522 }
523 let triggerHeartbeatRestart = false;
524 if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) {
525 ChargingStationConfigurationUtils.setConfigurationKeyValue(
526 chargingStation,
527 OCPP16StandardParametersKey.HeartbeatInterval,
528 commandPayload.value
529 );
530 triggerHeartbeatRestart = true;
531 }
532 if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) {
533 ChargingStationConfigurationUtils.setConfigurationKeyValue(
534 chargingStation,
535 OCPP16StandardParametersKey.HeartBeatInterval,
536 commandPayload.value
537 );
538 triggerHeartbeatRestart = true;
539 }
540 if (triggerHeartbeatRestart) {
541 chargingStation.restartHeartbeat();
542 }
543 if (keyToChange.key === OCPP16StandardParametersKey.WebSocketPingInterval && valueChanged) {
544 chargingStation.restartWebSocketPing();
545 }
546 if (keyToChange.reboot) {
547 return Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED;
548 }
549 return Constants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED;
550 }
551 }
552
553 private handleRequestSetChargingProfile(
554 chargingStation: ChargingStation,
555 commandPayload: SetChargingProfileRequest
556 ): SetChargingProfileResponse {
557 if (
558 OCPP16ServiceUtils.checkFeatureProfile(
559 chargingStation,
560 OCPP16SupportedFeatureProfiles.SmartCharging,
561 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE
562 ) === false
563 ) {
564 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED;
565 }
566 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
567 logger.error(
568 `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${
569 commandPayload.connectorId
570 }`
571 );
572 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
573 }
574 if (
575 commandPayload.csChargingProfiles.chargingProfilePurpose ===
576 ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE &&
577 commandPayload.connectorId !== 0
578 ) {
579 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
580 }
581 if (
582 commandPayload.csChargingProfiles.chargingProfilePurpose ===
583 ChargingProfilePurposeType.TX_PROFILE &&
584 (commandPayload.connectorId === 0 ||
585 chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted ===
586 false)
587 ) {
588 logger.error(
589 `${chargingStation.logPrefix()} Trying to set transaction charging profile(s) on connector ${
590 commandPayload.connectorId
591 } without a started transaction`
592 );
593 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
594 }
595 OCPP16ServiceUtils.setChargingProfile(
596 chargingStation,
597 commandPayload.connectorId,
598 commandPayload.csChargingProfiles
599 );
600 logger.debug(
601 `${chargingStation.logPrefix()} Charging profile(s) set on connector id ${
602 commandPayload.connectorId
603 }, dump their stack: %j`,
604 chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
605 );
606 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
607 }
608
609 private handleRequestClearChargingProfile(
610 chargingStation: ChargingStation,
611 commandPayload: ClearChargingProfileRequest
612 ): ClearChargingProfileResponse {
613 if (
614 OCPP16ServiceUtils.checkFeatureProfile(
615 chargingStation,
616 OCPP16SupportedFeatureProfiles.SmartCharging,
617 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE
618 ) === false
619 ) {
620 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
621 }
622 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
623 logger.error(
624 `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${
625 commandPayload.connectorId
626 }`
627 );
628 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
629 }
630 const connectorStatus = chargingStation.getConnectorStatus(commandPayload.connectorId);
631 if (commandPayload.connectorId && !Utils.isEmptyArray(connectorStatus.chargingProfiles)) {
632 connectorStatus.chargingProfiles = [];
633 logger.debug(
634 `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
635 commandPayload.connectorId
636 }, dump their stack: %j`,
637 connectorStatus.chargingProfiles
638 );
639 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
640 }
641 if (!commandPayload.connectorId) {
642 let clearedCP = false;
643 for (const connectorId of chargingStation.connectors.keys()) {
644 if (!Utils.isEmptyArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) {
645 chargingStation
646 .getConnectorStatus(connectorId)
647 .chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
648 let clearCurrentCP = false;
649 if (chargingProfile.chargingProfileId === commandPayload.id) {
650 clearCurrentCP = true;
651 }
652 if (
653 !commandPayload.chargingProfilePurpose &&
654 chargingProfile.stackLevel === commandPayload.stackLevel
655 ) {
656 clearCurrentCP = true;
657 }
658 if (
659 !chargingProfile.stackLevel &&
660 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
661 ) {
662 clearCurrentCP = true;
663 }
664 if (
665 chargingProfile.stackLevel === commandPayload.stackLevel &&
666 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
667 ) {
668 clearCurrentCP = true;
669 }
670 if (clearCurrentCP) {
671 connectorStatus.chargingProfiles.splice(index, 1);
672 logger.debug(
673 `${chargingStation.logPrefix()} Matching charging profile(s) cleared on connector id ${
674 commandPayload.connectorId
675 }, dump their stack: %j`,
676 connectorStatus.chargingProfiles
677 );
678 clearedCP = true;
679 }
680 });
681 }
682 }
683 if (clearedCP) {
684 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
685 }
686 }
687 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
688 }
689
690 private async handleRequestChangeAvailability(
691 chargingStation: ChargingStation,
692 commandPayload: ChangeAvailabilityRequest
693 ): Promise<ChangeAvailabilityResponse> {
694 const connectorId: number = commandPayload.connectorId;
695 if (chargingStation.connectors.has(connectorId) === false) {
696 logger.error(
697 `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`
698 );
699 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
700 }
701 const chargePointStatus: OCPP16ChargePointStatus =
702 commandPayload.type === OCPP16AvailabilityType.OPERATIVE
703 ? OCPP16ChargePointStatus.AVAILABLE
704 : OCPP16ChargePointStatus.UNAVAILABLE;
705 if (connectorId === 0) {
706 let response: ChangeAvailabilityResponse = Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
707 for (const id of chargingStation.connectors.keys()) {
708 if (chargingStation.getConnectorStatus(id)?.transactionStarted === true) {
709 response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
710 }
711 chargingStation.getConnectorStatus(id).availability = commandPayload.type;
712 if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
713 await chargingStation.ocppRequestService.requestHandler<
714 OCPP16StatusNotificationRequest,
715 OCPP16StatusNotificationResponse
716 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
717 connectorId: id,
718 status: chargePointStatus,
719 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
720 });
721 chargingStation.getConnectorStatus(id).status = chargePointStatus;
722 }
723 }
724 return response;
725 } else if (
726 connectorId > 0 &&
727 (chargingStation.isChargingStationAvailable() === true ||
728 (chargingStation.isChargingStationAvailable() === false &&
729 commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))
730 ) {
731 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
732 chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
733 return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
734 }
735 chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
736 await chargingStation.ocppRequestService.requestHandler<
737 OCPP16StatusNotificationRequest,
738 OCPP16StatusNotificationResponse
739 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
740 connectorId,
741 status: chargePointStatus,
742 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
743 });
744 chargingStation.getConnectorStatus(connectorId).status = chargePointStatus;
745 return Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
746 }
747 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
748 }
749
750 private async handleRequestRemoteStartTransaction(
751 chargingStation: ChargingStation,
752 commandPayload: RemoteStartTransactionRequest
753 ): Promise<DefaultResponse> {
754 const transactionConnectorId = commandPayload.connectorId;
755 if (chargingStation.connectors.has(transactionConnectorId) === true) {
756 const remoteStartTransactionLogMsg =
757 chargingStation.logPrefix() +
758 ' Transaction remotely STARTED on ' +
759 chargingStation.stationInfo.chargingStationId +
760 '#' +
761 transactionConnectorId.toString() +
762 " for idTag '" +
763 commandPayload.idTag +
764 "'";
765 await chargingStation.ocppRequestService.requestHandler<
766 OCPP16StatusNotificationRequest,
767 OCPP16StatusNotificationResponse
768 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
769 connectorId: transactionConnectorId,
770 status: OCPP16ChargePointStatus.PREPARING,
771 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
772 });
773 const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId);
774 connectorStatus.status = OCPP16ChargePointStatus.PREPARING;
775 if (chargingStation.isChargingStationAvailable() === true) {
776 // Check if authorized
777 if (chargingStation.getAuthorizeRemoteTxRequests() === true) {
778 let authorized = false;
779 if (
780 chargingStation.getLocalAuthListEnabled() === true &&
781 chargingStation.hasAuthorizedTags() === true &&
782 chargingStation.authorizedTagsCache
783 .getAuthorizedTags(
784 ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo)
785 )
786 .find((idTag) => idTag === commandPayload.idTag)
787 ) {
788 connectorStatus.localAuthorizeIdTag = commandPayload.idTag;
789 connectorStatus.idTagLocalAuthorized = true;
790 authorized = true;
791 } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
792 connectorStatus.authorizeIdTag = commandPayload.idTag;
793 const authorizeResponse: OCPP16AuthorizeResponse =
794 await chargingStation.ocppRequestService.requestHandler<
795 OCPP16AuthorizeRequest,
796 OCPP16AuthorizeResponse
797 >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
798 idTag: commandPayload.idTag,
799 });
800 if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
801 authorized = true;
802 }
803 } else {
804 logger.warn(
805 `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
806 );
807 }
808 if (authorized === true) {
809 // Authorization successful, start transaction
810 if (
811 this.setRemoteStartTransactionChargingProfile(
812 chargingStation,
813 transactionConnectorId,
814 commandPayload.chargingProfile
815 ) === true
816 ) {
817 connectorStatus.transactionRemoteStarted = true;
818 if (
819 (
820 await chargingStation.ocppRequestService.requestHandler<
821 OCPP16StartTransactionRequest,
822 OCPP16StartTransactionResponse
823 >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
824 connectorId: transactionConnectorId,
825 idTag: commandPayload.idTag,
826 })
827 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
828 ) {
829 logger.debug(remoteStartTransactionLogMsg);
830 return Constants.OCPP_RESPONSE_ACCEPTED;
831 }
832 return this.notifyRemoteStartTransactionRejected(
833 chargingStation,
834 transactionConnectorId,
835 commandPayload.idTag
836 );
837 }
838 return this.notifyRemoteStartTransactionRejected(
839 chargingStation,
840 transactionConnectorId,
841 commandPayload.idTag
842 );
843 }
844 return this.notifyRemoteStartTransactionRejected(
845 chargingStation,
846 transactionConnectorId,
847 commandPayload.idTag
848 );
849 }
850 // No authorization check required, start transaction
851 if (
852 this.setRemoteStartTransactionChargingProfile(
853 chargingStation,
854 transactionConnectorId,
855 commandPayload.chargingProfile
856 ) === true
857 ) {
858 connectorStatus.transactionRemoteStarted = true;
859 if (
860 (
861 await chargingStation.ocppRequestService.requestHandler<
862 OCPP16StartTransactionRequest,
863 OCPP16StartTransactionResponse
864 >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
865 connectorId: transactionConnectorId,
866 idTag: commandPayload.idTag,
867 })
868 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
869 ) {
870 logger.debug(remoteStartTransactionLogMsg);
871 return Constants.OCPP_RESPONSE_ACCEPTED;
872 }
873 return this.notifyRemoteStartTransactionRejected(
874 chargingStation,
875 transactionConnectorId,
876 commandPayload.idTag
877 );
878 }
879 return this.notifyRemoteStartTransactionRejected(
880 chargingStation,
881 transactionConnectorId,
882 commandPayload.idTag
883 );
884 }
885 return this.notifyRemoteStartTransactionRejected(
886 chargingStation,
887 transactionConnectorId,
888 commandPayload.idTag
889 );
890 }
891 return this.notifyRemoteStartTransactionRejected(
892 chargingStation,
893 transactionConnectorId,
894 commandPayload.idTag
895 );
896 }
897
898 private async notifyRemoteStartTransactionRejected(
899 chargingStation: ChargingStation,
900 connectorId: number,
901 idTag: string
902 ): Promise<DefaultResponse> {
903 if (
904 chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE
905 ) {
906 await chargingStation.ocppRequestService.requestHandler<
907 OCPP16StatusNotificationRequest,
908 OCPP16StatusNotificationResponse
909 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
910 connectorId,
911 status: OCPP16ChargePointStatus.AVAILABLE,
912 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
913 });
914 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
915 }
916 logger.warn(
917 chargingStation.logPrefix() +
918 ' Remote starting transaction REJECTED on connector Id ' +
919 connectorId.toString() +
920 ", idTag '" +
921 idTag +
922 "', availability '" +
923 chargingStation.getConnectorStatus(connectorId).availability +
924 "', status '" +
925 chargingStation.getConnectorStatus(connectorId).status +
926 "'"
927 );
928 return Constants.OCPP_RESPONSE_REJECTED;
929 }
930
931 private setRemoteStartTransactionChargingProfile(
932 chargingStation: ChargingStation,
933 connectorId: number,
934 cp: OCPP16ChargingProfile
935 ): boolean {
936 if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
937 OCPP16ServiceUtils.setChargingProfile(chargingStation, connectorId, cp);
938 logger.debug(
939 `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}, dump their stack: %j`,
940 chargingStation.getConnectorStatus(connectorId).chargingProfiles
941 );
942 return true;
943 } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) {
944 logger.warn(
945 `${chargingStation.logPrefix()} Not allowed to set ${
946 cp.chargingProfilePurpose
947 } charging profile(s) at remote start transaction`
948 );
949 return false;
950 } else if (!cp) {
951 return true;
952 }
953 }
954
955 private async handleRequestRemoteStopTransaction(
956 chargingStation: ChargingStation,
957 commandPayload: RemoteStopTransactionRequest
958 ): Promise<DefaultResponse> {
959 const transactionId = commandPayload.transactionId;
960 for (const connectorId of chargingStation.connectors.keys()) {
961 if (
962 connectorId > 0 &&
963 chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
964 ) {
965 await chargingStation.ocppRequestService.requestHandler<
966 OCPP16StatusNotificationRequest,
967 OCPP16StatusNotificationResponse
968 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
969 connectorId,
970 status: OCPP16ChargePointStatus.FINISHING,
971 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
972 });
973 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.FINISHING;
974 const stopResponse = await chargingStation.stopTransactionOnConnector(
975 connectorId,
976 OCPP16StopTransactionReason.REMOTE
977 );
978 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
979 return Constants.OCPP_RESPONSE_ACCEPTED;
980 }
981 return Constants.OCPP_RESPONSE_REJECTED;
982 }
983 }
984 logger.warn(
985 chargingStation.logPrefix() +
986 ' Trying to remote stop a non existing transaction ' +
987 transactionId.toString()
988 );
989 return Constants.OCPP_RESPONSE_REJECTED;
990 }
991
992 private async handleRequestGetDiagnostics(
993 chargingStation: ChargingStation,
994 commandPayload: GetDiagnosticsRequest
995 ): Promise<GetDiagnosticsResponse> {
996 if (
997 OCPP16ServiceUtils.checkFeatureProfile(
998 chargingStation,
999 OCPP16SupportedFeatureProfiles.FirmwareManagement,
1000 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1001 ) === false
1002 ) {
1003 return Constants.OCPP_RESPONSE_EMPTY;
1004 }
1005 logger.debug(
1006 chargingStation.logPrefix() +
1007 ' ' +
1008 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS +
1009 ' request received: %j',
1010 commandPayload
1011 );
1012 const uri = new URL(commandPayload.location);
1013 if (uri.protocol.startsWith('ftp:')) {
1014 let ftpClient: Client;
1015 try {
1016 const logFiles = fs
1017 .readdirSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'))
1018 .filter((file) => file.endsWith('.log'))
1019 .map((file) => path.join('./', file));
1020 const diagnosticsArchive = chargingStation.stationInfo.chargingStationId + '_logs.tar.gz';
1021 tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
1022 ftpClient = new Client();
1023 const accessResponse = await ftpClient.access({
1024 host: uri.host,
1025 ...(!Utils.isEmptyString(uri.port) && { port: Utils.convertToInt(uri.port) }),
1026 ...(!Utils.isEmptyString(uri.username) && { user: uri.username }),
1027 ...(!Utils.isEmptyString(uri.password) && { password: uri.password }),
1028 });
1029 let uploadResponse: FTPResponse;
1030 if (accessResponse.code === 220) {
1031 // eslint-disable-next-line @typescript-eslint/no-misused-promises
1032 ftpClient.trackProgress(async (info) => {
1033 logger.info(
1034 `${chargingStation.logPrefix()} ${
1035 info.bytes / 1024
1036 } bytes transferred from diagnostics archive ${info.name}`
1037 );
1038 await chargingStation.ocppRequestService.requestHandler<
1039 DiagnosticsStatusNotificationRequest,
1040 DiagnosticsStatusNotificationResponse
1041 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1042 status: OCPP16DiagnosticsStatus.Uploading,
1043 });
1044 });
1045 uploadResponse = await ftpClient.uploadFrom(
1046 path.join(
1047 path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'),
1048 diagnosticsArchive
1049 ),
1050 uri.pathname + diagnosticsArchive
1051 );
1052 if (uploadResponse.code === 226) {
1053 await chargingStation.ocppRequestService.requestHandler<
1054 DiagnosticsStatusNotificationRequest,
1055 DiagnosticsStatusNotificationResponse
1056 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1057 status: OCPP16DiagnosticsStatus.Uploaded,
1058 });
1059 if (ftpClient) {
1060 ftpClient.close();
1061 }
1062 return { fileName: diagnosticsArchive };
1063 }
1064 throw new OCPPError(
1065 ErrorType.GENERIC_ERROR,
1066 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1067 uploadResponse?.code && '|' + uploadResponse?.code.toString()
1068 }`,
1069 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1070 );
1071 }
1072 throw new OCPPError(
1073 ErrorType.GENERIC_ERROR,
1074 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1075 uploadResponse?.code && '|' + uploadResponse?.code.toString()
1076 }`,
1077 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1078 );
1079 } catch (error) {
1080 await chargingStation.ocppRequestService.requestHandler<
1081 DiagnosticsStatusNotificationRequest,
1082 DiagnosticsStatusNotificationResponse
1083 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1084 status: OCPP16DiagnosticsStatus.UploadFailed,
1085 });
1086 if (ftpClient) {
1087 ftpClient.close();
1088 }
1089 return this.handleIncomingRequestError(
1090 chargingStation,
1091 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
1092 error as Error,
1093 { errorResponse: Constants.OCPP_RESPONSE_EMPTY }
1094 );
1095 }
1096 } else {
1097 logger.error(
1098 `${chargingStation.logPrefix()} Unsupported protocol ${
1099 uri.protocol
1100 } to transfer the diagnostic logs archive`
1101 );
1102 await chargingStation.ocppRequestService.requestHandler<
1103 DiagnosticsStatusNotificationRequest,
1104 DiagnosticsStatusNotificationResponse
1105 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1106 status: OCPP16DiagnosticsStatus.UploadFailed,
1107 });
1108 return Constants.OCPP_RESPONSE_EMPTY;
1109 }
1110 }
1111
1112 private handleRequestTriggerMessage(
1113 chargingStation: ChargingStation,
1114 commandPayload: OCPP16TriggerMessageRequest
1115 ): OCPP16TriggerMessageResponse {
1116 if (
1117 !OCPP16ServiceUtils.checkFeatureProfile(
1118 chargingStation,
1119 OCPP16SupportedFeatureProfiles.RemoteTrigger,
1120 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
1121 ) ||
1122 !OCPP16ServiceUtils.isMessageTriggerSupported(
1123 chargingStation,
1124 commandPayload.requestedMessage
1125 )
1126 ) {
1127 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
1128 }
1129 if (
1130 !OCPP16ServiceUtils.isConnectorIdValid(
1131 chargingStation,
1132 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
1133 commandPayload.connectorId
1134 )
1135 ) {
1136 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED;
1137 }
1138 try {
1139 switch (commandPayload.requestedMessage) {
1140 case OCPP16MessageTrigger.BootNotification:
1141 setTimeout(() => {
1142 chargingStation.ocppRequestService
1143 .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
1144 chargingStation,
1145 OCPP16RequestCommand.BOOT_NOTIFICATION,
1146 chargingStation.bootNotificationRequest,
1147 { skipBufferingOnError: true, triggerMessage: true }
1148 )
1149 .then((response) => {
1150 chargingStation.bootNotificationResponse = response;
1151 })
1152 .catch(() => {
1153 /* This is intentional */
1154 });
1155 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1156 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
1157 case OCPP16MessageTrigger.Heartbeat:
1158 setTimeout(() => {
1159 chargingStation.ocppRequestService
1160 .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
1161 chargingStation,
1162 OCPP16RequestCommand.HEARTBEAT,
1163 null,
1164 {
1165 triggerMessage: true,
1166 }
1167 )
1168 .catch(() => {
1169 /* This is intentional */
1170 });
1171 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1172 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
1173 case OCPP16MessageTrigger.StatusNotification:
1174 setTimeout(() => {
1175 if (commandPayload?.connectorId) {
1176 chargingStation.ocppRequestService
1177 .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
1178 chargingStation,
1179 OCPP16RequestCommand.STATUS_NOTIFICATION,
1180 {
1181 connectorId: commandPayload.connectorId,
1182 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1183 status: chargingStation.getConnectorStatus(commandPayload.connectorId).status,
1184 },
1185 {
1186 triggerMessage: true,
1187 }
1188 )
1189 .catch(() => {
1190 /* This is intentional */
1191 });
1192 } else {
1193 for (const connectorId of chargingStation.connectors.keys()) {
1194 chargingStation.ocppRequestService
1195 .requestHandler<
1196 OCPP16StatusNotificationRequest,
1197 OCPP16StatusNotificationResponse
1198 >(
1199 chargingStation,
1200 OCPP16RequestCommand.STATUS_NOTIFICATION,
1201 {
1202 connectorId,
1203 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1204 status: chargingStation.getConnectorStatus(connectorId).status,
1205 },
1206 {
1207 triggerMessage: true,
1208 }
1209 )
1210 .catch(() => {
1211 /* This is intentional */
1212 });
1213 }
1214 }
1215 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1216 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
1217 default:
1218 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
1219 }
1220 } catch (error) {
1221 return this.handleIncomingRequestError(
1222 chargingStation,
1223 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
1224 error as Error,
1225 { errorResponse: Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED }
1226 );
1227 }
1228 }
1229 }