Log error at faulty profile sent
[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 MessageTrigger,
32 OCPP16AvailabilityType,
33 OCPP16BootNotificationRequest,
34 OCPP16ClearCacheRequest,
35 OCPP16HeartbeatRequest,
36 OCPP16IncomingRequestCommand,
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() &&
285 chargingStation.isInPendingState() &&
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.runInAsyncScope(
383 chargingStation.reset.bind(chargingStation) as (
384 this: ChargingStation,
385 ...args: any[]
386 ) => void,
387 chargingStation,
388 (commandPayload.type + 'Reset') as OCPP16StopTransactionReason
389 );
390 logger.info(
391 `${chargingStation.logPrefix()} ${
392 commandPayload.type
393 } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
394 chargingStation.stationInfo.resetTime
395 )}`
396 );
397 return Constants.OCPP_RESPONSE_ACCEPTED;
398 }
399
400 private handleRequestClearCache(chargingStation: ChargingStation): DefaultResponse {
401 chargingStation.authorizedTagsCache.deleteAuthorizedTags(
402 ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo)
403 );
404 return Constants.OCPP_RESPONSE_ACCEPTED;
405 }
406
407 private async handleRequestUnlockConnector(
408 chargingStation: ChargingStation,
409 commandPayload: UnlockConnectorRequest
410 ): Promise<UnlockConnectorResponse> {
411 const connectorId = commandPayload.connectorId;
412 if (connectorId === 0) {
413 logger.error(
414 chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString()
415 );
416 return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
417 }
418 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
419 const stopResponse = await chargingStation.stopTransactionOnConnector(
420 connectorId,
421 OCPP16StopTransactionReason.UNLOCK_COMMAND
422 );
423 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
424 return Constants.OCPP_RESPONSE_UNLOCKED;
425 }
426 return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
427 }
428 await chargingStation.ocppRequestService.requestHandler<
429 OCPP16StatusNotificationRequest,
430 OCPP16StatusNotificationResponse
431 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
432 connectorId,
433 status: OCPP16ChargePointStatus.AVAILABLE,
434 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
435 });
436 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
437 return Constants.OCPP_RESPONSE_UNLOCKED;
438 }
439
440 private handleRequestGetConfiguration(
441 chargingStation: ChargingStation,
442 commandPayload: GetConfigurationRequest
443 ): GetConfigurationResponse {
444 const configurationKey: OCPPConfigurationKey[] = [];
445 const unknownKey: string[] = [];
446 if (Utils.isEmptyArray(commandPayload.key) === true) {
447 for (const configuration of chargingStation.ocppConfiguration.configurationKey) {
448 if (Utils.isUndefined(configuration.visible) === true) {
449 configuration.visible = true;
450 }
451 if (configuration.visible === false) {
452 continue;
453 }
454 configurationKey.push({
455 key: configuration.key,
456 readonly: configuration.readonly,
457 value: configuration.value,
458 });
459 }
460 } else {
461 for (const key of commandPayload.key) {
462 const keyFound = ChargingStationConfigurationUtils.getConfigurationKey(
463 chargingStation,
464 key
465 );
466 if (keyFound) {
467 if (Utils.isUndefined(keyFound.visible) === true) {
468 keyFound.visible = true;
469 }
470 if (keyFound.visible === false) {
471 continue;
472 }
473 configurationKey.push({
474 key: keyFound.key,
475 readonly: keyFound.readonly,
476 value: keyFound.value,
477 });
478 } else {
479 unknownKey.push(key);
480 }
481 }
482 }
483 return {
484 configurationKey,
485 unknownKey,
486 };
487 }
488
489 private handleRequestChangeConfiguration(
490 chargingStation: ChargingStation,
491 commandPayload: ChangeConfigurationRequest
492 ): ChangeConfigurationResponse {
493 const keyToChange = ChargingStationConfigurationUtils.getConfigurationKey(
494 chargingStation,
495 commandPayload.key,
496 true
497 );
498 if (!keyToChange) {
499 return Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED;
500 } else if (keyToChange && keyToChange.readonly) {
501 return Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED;
502 } else if (keyToChange && !keyToChange.readonly) {
503 let valueChanged = false;
504 if (keyToChange.value !== commandPayload.value) {
505 ChargingStationConfigurationUtils.setConfigurationKeyValue(
506 chargingStation,
507 commandPayload.key,
508 commandPayload.value,
509 true
510 );
511 valueChanged = true;
512 }
513 let triggerHeartbeatRestart = false;
514 if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) {
515 ChargingStationConfigurationUtils.setConfigurationKeyValue(
516 chargingStation,
517 OCPP16StandardParametersKey.HeartbeatInterval,
518 commandPayload.value
519 );
520 triggerHeartbeatRestart = true;
521 }
522 if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) {
523 ChargingStationConfigurationUtils.setConfigurationKeyValue(
524 chargingStation,
525 OCPP16StandardParametersKey.HeartBeatInterval,
526 commandPayload.value
527 );
528 triggerHeartbeatRestart = true;
529 }
530 if (triggerHeartbeatRestart) {
531 chargingStation.restartHeartbeat();
532 }
533 if (keyToChange.key === OCPP16StandardParametersKey.WebSocketPingInterval && valueChanged) {
534 chargingStation.restartWebSocketPing();
535 }
536 if (keyToChange.reboot) {
537 return Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED;
538 }
539 return Constants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED;
540 }
541 }
542
543 private handleRequestSetChargingProfile(
544 chargingStation: ChargingStation,
545 commandPayload: SetChargingProfileRequest
546 ): SetChargingProfileResponse {
547 if (
548 OCPP16ServiceUtils.checkFeatureProfile(
549 chargingStation,
550 OCPP16SupportedFeatureProfiles.SmartCharging,
551 OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE
552 ) === false
553 ) {
554 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED;
555 }
556 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
557 logger.error(
558 `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${
559 commandPayload.connectorId
560 }`
561 );
562 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
563 }
564 if (
565 commandPayload.csChargingProfiles.chargingProfilePurpose ===
566 ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE &&
567 commandPayload.connectorId !== 0
568 ) {
569 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
570 }
571 if (
572 commandPayload.csChargingProfiles.chargingProfilePurpose ===
573 ChargingProfilePurposeType.TX_PROFILE &&
574 (commandPayload.connectorId === 0 ||
575 chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted ===
576 false)
577 ) {
578 logger.error(
579 `${chargingStation.logPrefix()} Trying to set transaction charging profile(s) on connector ${
580 commandPayload.connectorId
581 } without a started transaction`
582 );
583 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
584 }
585 OCPP16ServiceUtils.setChargingProfile(
586 chargingStation,
587 commandPayload.connectorId,
588 commandPayload.csChargingProfiles
589 );
590 logger.debug(
591 `${chargingStation.logPrefix()} Charging profile(s) set on connector id ${
592 commandPayload.connectorId
593 }, dump their stack: %j`,
594 chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
595 );
596 return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
597 }
598
599 private handleRequestClearChargingProfile(
600 chargingStation: ChargingStation,
601 commandPayload: ClearChargingProfileRequest
602 ): ClearChargingProfileResponse {
603 if (
604 OCPP16ServiceUtils.checkFeatureProfile(
605 chargingStation,
606 OCPP16SupportedFeatureProfiles.SmartCharging,
607 OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE
608 ) === false
609 ) {
610 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
611 }
612 if (chargingStation.connectors.has(commandPayload.connectorId) === false) {
613 logger.error(
614 `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${
615 commandPayload.connectorId
616 }`
617 );
618 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
619 }
620 const connectorStatus = chargingStation.getConnectorStatus(commandPayload.connectorId);
621 if (commandPayload.connectorId && !Utils.isEmptyArray(connectorStatus.chargingProfiles)) {
622 connectorStatus.chargingProfiles = [];
623 logger.debug(
624 `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
625 commandPayload.connectorId
626 }, dump their stack: %j`,
627 connectorStatus.chargingProfiles
628 );
629 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
630 }
631 if (!commandPayload.connectorId) {
632 let clearedCP = false;
633 for (const connectorId of chargingStation.connectors.keys()) {
634 if (!Utils.isEmptyArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) {
635 chargingStation
636 .getConnectorStatus(connectorId)
637 .chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
638 let clearCurrentCP = false;
639 if (chargingProfile.chargingProfileId === commandPayload.id) {
640 clearCurrentCP = true;
641 }
642 if (
643 !commandPayload.chargingProfilePurpose &&
644 chargingProfile.stackLevel === commandPayload.stackLevel
645 ) {
646 clearCurrentCP = true;
647 }
648 if (
649 !chargingProfile.stackLevel &&
650 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
651 ) {
652 clearCurrentCP = true;
653 }
654 if (
655 chargingProfile.stackLevel === commandPayload.stackLevel &&
656 chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
657 ) {
658 clearCurrentCP = true;
659 }
660 if (clearCurrentCP) {
661 connectorStatus.chargingProfiles.splice(index, 1);
662 logger.debug(
663 `${chargingStation.logPrefix()} Matching charging profile(s) cleared on connector id ${
664 commandPayload.connectorId
665 }, dump their stack: %j`,
666 connectorStatus.chargingProfiles
667 );
668 clearedCP = true;
669 }
670 });
671 }
672 }
673 if (clearedCP) {
674 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
675 }
676 }
677 return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
678 }
679
680 private async handleRequestChangeAvailability(
681 chargingStation: ChargingStation,
682 commandPayload: ChangeAvailabilityRequest
683 ): Promise<ChangeAvailabilityResponse> {
684 const connectorId: number = commandPayload.connectorId;
685 if (!chargingStation.getConnectorStatus(connectorId)) {
686 logger.error(
687 `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`
688 );
689 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
690 }
691 const chargePointStatus: OCPP16ChargePointStatus =
692 commandPayload.type === OCPP16AvailabilityType.OPERATIVE
693 ? OCPP16ChargePointStatus.AVAILABLE
694 : OCPP16ChargePointStatus.UNAVAILABLE;
695 if (connectorId === 0) {
696 let response: ChangeAvailabilityResponse = Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
697 for (const id of chargingStation.connectors.keys()) {
698 if (chargingStation.getConnectorStatus(id)?.transactionStarted === true) {
699 response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
700 }
701 chargingStation.getConnectorStatus(id).availability = commandPayload.type;
702 if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
703 await chargingStation.ocppRequestService.requestHandler<
704 OCPP16StatusNotificationRequest,
705 OCPP16StatusNotificationResponse
706 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
707 connectorId: id,
708 status: chargePointStatus,
709 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
710 });
711 chargingStation.getConnectorStatus(id).status = chargePointStatus;
712 }
713 }
714 return response;
715 } else if (
716 connectorId > 0 &&
717 (chargingStation.isChargingStationAvailable() === true ||
718 (chargingStation.isChargingStationAvailable() === false &&
719 commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))
720 ) {
721 if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) {
722 chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
723 return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
724 }
725 chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
726 await chargingStation.ocppRequestService.requestHandler<
727 OCPP16StatusNotificationRequest,
728 OCPP16StatusNotificationResponse
729 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
730 connectorId,
731 status: chargePointStatus,
732 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
733 });
734 chargingStation.getConnectorStatus(connectorId).status = chargePointStatus;
735 return Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
736 }
737 return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
738 }
739
740 private async handleRequestRemoteStartTransaction(
741 chargingStation: ChargingStation,
742 commandPayload: RemoteStartTransactionRequest
743 ): Promise<DefaultResponse> {
744 const transactionConnectorId = commandPayload.connectorId;
745 if (chargingStation.connectors.has(transactionConnectorId) === true) {
746 const remoteStartTransactionLogMsg =
747 chargingStation.logPrefix() +
748 ' Transaction remotely STARTED on ' +
749 chargingStation.stationInfo.chargingStationId +
750 '#' +
751 transactionConnectorId.toString() +
752 " for idTag '" +
753 commandPayload.idTag +
754 "'";
755 await chargingStation.ocppRequestService.requestHandler<
756 OCPP16StatusNotificationRequest,
757 OCPP16StatusNotificationResponse
758 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
759 connectorId: transactionConnectorId,
760 status: OCPP16ChargePointStatus.PREPARING,
761 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
762 });
763 const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId);
764 connectorStatus.status = OCPP16ChargePointStatus.PREPARING;
765 if (chargingStation.isChargingStationAvailable() === true) {
766 // Check if authorized
767 if (chargingStation.getAuthorizeRemoteTxRequests() === true) {
768 let authorized = false;
769 if (
770 chargingStation.getLocalAuthListEnabled() === true &&
771 chargingStation.hasAuthorizedTags() === true &&
772 chargingStation.authorizedTagsCache
773 .getAuthorizedTags(
774 ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo)
775 )
776 .find((idTag) => idTag === commandPayload.idTag)
777 ) {
778 connectorStatus.localAuthorizeIdTag = commandPayload.idTag;
779 connectorStatus.idTagLocalAuthorized = true;
780 authorized = true;
781 } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
782 connectorStatus.authorizeIdTag = commandPayload.idTag;
783 const authorizeResponse: OCPP16AuthorizeResponse =
784 await chargingStation.ocppRequestService.requestHandler<
785 OCPP16AuthorizeRequest,
786 OCPP16AuthorizeResponse
787 >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
788 idTag: commandPayload.idTag,
789 });
790 if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
791 authorized = true;
792 }
793 } else {
794 logger.warn(
795 `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
796 );
797 }
798 if (authorized === true) {
799 // Authorization successful, start transaction
800 if (
801 this.setRemoteStartTransactionChargingProfile(
802 chargingStation,
803 transactionConnectorId,
804 commandPayload.chargingProfile
805 ) === true
806 ) {
807 connectorStatus.transactionRemoteStarted = true;
808 if (
809 (
810 await chargingStation.ocppRequestService.requestHandler<
811 OCPP16StartTransactionRequest,
812 OCPP16StartTransactionResponse
813 >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
814 connectorId: transactionConnectorId,
815 idTag: commandPayload.idTag,
816 })
817 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
818 ) {
819 logger.debug(remoteStartTransactionLogMsg);
820 return Constants.OCPP_RESPONSE_ACCEPTED;
821 }
822 return this.notifyRemoteStartTransactionRejected(
823 chargingStation,
824 transactionConnectorId,
825 commandPayload.idTag
826 );
827 }
828 return this.notifyRemoteStartTransactionRejected(
829 chargingStation,
830 transactionConnectorId,
831 commandPayload.idTag
832 );
833 }
834 return this.notifyRemoteStartTransactionRejected(
835 chargingStation,
836 transactionConnectorId,
837 commandPayload.idTag
838 );
839 }
840 // No authorization check required, start transaction
841 if (
842 this.setRemoteStartTransactionChargingProfile(
843 chargingStation,
844 transactionConnectorId,
845 commandPayload.chargingProfile
846 ) === true
847 ) {
848 connectorStatus.transactionRemoteStarted = true;
849 if (
850 (
851 await chargingStation.ocppRequestService.requestHandler<
852 OCPP16StartTransactionRequest,
853 OCPP16StartTransactionResponse
854 >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, {
855 connectorId: transactionConnectorId,
856 idTag: commandPayload.idTag,
857 })
858 ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
859 ) {
860 logger.debug(remoteStartTransactionLogMsg);
861 return Constants.OCPP_RESPONSE_ACCEPTED;
862 }
863 return this.notifyRemoteStartTransactionRejected(
864 chargingStation,
865 transactionConnectorId,
866 commandPayload.idTag
867 );
868 }
869 return this.notifyRemoteStartTransactionRejected(
870 chargingStation,
871 transactionConnectorId,
872 commandPayload.idTag
873 );
874 }
875 return this.notifyRemoteStartTransactionRejected(
876 chargingStation,
877 transactionConnectorId,
878 commandPayload.idTag
879 );
880 }
881 return this.notifyRemoteStartTransactionRejected(
882 chargingStation,
883 transactionConnectorId,
884 commandPayload.idTag
885 );
886 }
887
888 private async notifyRemoteStartTransactionRejected(
889 chargingStation: ChargingStation,
890 connectorId: number,
891 idTag: string
892 ): Promise<DefaultResponse> {
893 if (
894 chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE
895 ) {
896 await chargingStation.ocppRequestService.requestHandler<
897 OCPP16StatusNotificationRequest,
898 OCPP16StatusNotificationResponse
899 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
900 connectorId,
901 status: OCPP16ChargePointStatus.AVAILABLE,
902 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
903 });
904 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
905 }
906 logger.warn(
907 chargingStation.logPrefix() +
908 ' Remote starting transaction REJECTED on connector Id ' +
909 connectorId.toString() +
910 ", idTag '" +
911 idTag +
912 "', availability '" +
913 chargingStation.getConnectorStatus(connectorId).availability +
914 "', status '" +
915 chargingStation.getConnectorStatus(connectorId).status +
916 "'"
917 );
918 return Constants.OCPP_RESPONSE_REJECTED;
919 }
920
921 private setRemoteStartTransactionChargingProfile(
922 chargingStation: ChargingStation,
923 connectorId: number,
924 cp: OCPP16ChargingProfile
925 ): boolean {
926 if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
927 OCPP16ServiceUtils.setChargingProfile(chargingStation, connectorId, cp);
928 logger.debug(
929 `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}, dump their stack: %j`,
930 chargingStation.getConnectorStatus(connectorId).chargingProfiles
931 );
932 return true;
933 } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) {
934 logger.warn(
935 `${chargingStation.logPrefix()} Not allowed to set ${
936 cp.chargingProfilePurpose
937 } charging profile(s) at remote start transaction`
938 );
939 return false;
940 } else if (!cp) {
941 return true;
942 }
943 }
944
945 private async handleRequestRemoteStopTransaction(
946 chargingStation: ChargingStation,
947 commandPayload: RemoteStopTransactionRequest
948 ): Promise<DefaultResponse> {
949 const transactionId = commandPayload.transactionId;
950 for (const connectorId of chargingStation.connectors.keys()) {
951 if (
952 connectorId > 0 &&
953 chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
954 ) {
955 await chargingStation.ocppRequestService.requestHandler<
956 OCPP16StatusNotificationRequest,
957 OCPP16StatusNotificationResponse
958 >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, {
959 connectorId,
960 status: OCPP16ChargePointStatus.FINISHING,
961 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
962 });
963 chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.FINISHING;
964 const stopResponse = await chargingStation.stopTransactionOnConnector(
965 connectorId,
966 OCPP16StopTransactionReason.REMOTE
967 );
968 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
969 return Constants.OCPP_RESPONSE_ACCEPTED;
970 }
971 return Constants.OCPP_RESPONSE_REJECTED;
972 }
973 }
974 logger.warn(
975 chargingStation.logPrefix() +
976 ' Trying to remote stop a non existing transaction ' +
977 transactionId.toString()
978 );
979 return Constants.OCPP_RESPONSE_REJECTED;
980 }
981
982 private async handleRequestGetDiagnostics(
983 chargingStation: ChargingStation,
984 commandPayload: GetDiagnosticsRequest
985 ): Promise<GetDiagnosticsResponse> {
986 if (
987 OCPP16ServiceUtils.checkFeatureProfile(
988 chargingStation,
989 OCPP16SupportedFeatureProfiles.FirmwareManagement,
990 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
991 ) === false
992 ) {
993 return Constants.OCPP_RESPONSE_EMPTY;
994 }
995 logger.debug(
996 chargingStation.logPrefix() +
997 ' ' +
998 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS +
999 ' request received: %j',
1000 commandPayload
1001 );
1002 const uri = new URL(commandPayload.location);
1003 if (uri.protocol.startsWith('ftp:')) {
1004 let ftpClient: Client;
1005 try {
1006 const logFiles = fs
1007 .readdirSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'))
1008 .filter((file) => file.endsWith('.log'))
1009 .map((file) => path.join('./', file));
1010 const diagnosticsArchive = chargingStation.stationInfo.chargingStationId + '_logs.tar.gz';
1011 tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
1012 ftpClient = new Client();
1013 const accessResponse = await ftpClient.access({
1014 host: uri.host,
1015 ...(!Utils.isEmptyString(uri.port) && { port: Utils.convertToInt(uri.port) }),
1016 ...(!Utils.isEmptyString(uri.username) && { user: uri.username }),
1017 ...(!Utils.isEmptyString(uri.password) && { password: uri.password }),
1018 });
1019 let uploadResponse: FTPResponse;
1020 if (accessResponse.code === 220) {
1021 // eslint-disable-next-line @typescript-eslint/no-misused-promises
1022 ftpClient.trackProgress(async (info) => {
1023 logger.info(
1024 `${chargingStation.logPrefix()} ${
1025 info.bytes / 1024
1026 } bytes transferred from diagnostics archive ${info.name}`
1027 );
1028 await chargingStation.ocppRequestService.requestHandler<
1029 DiagnosticsStatusNotificationRequest,
1030 DiagnosticsStatusNotificationResponse
1031 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1032 status: OCPP16DiagnosticsStatus.Uploading,
1033 });
1034 });
1035 uploadResponse = await ftpClient.uploadFrom(
1036 path.join(
1037 path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../'),
1038 diagnosticsArchive
1039 ),
1040 uri.pathname + diagnosticsArchive
1041 );
1042 if (uploadResponse.code === 226) {
1043 await chargingStation.ocppRequestService.requestHandler<
1044 DiagnosticsStatusNotificationRequest,
1045 DiagnosticsStatusNotificationResponse
1046 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1047 status: OCPP16DiagnosticsStatus.Uploaded,
1048 });
1049 if (ftpClient) {
1050 ftpClient.close();
1051 }
1052 return { fileName: diagnosticsArchive };
1053 }
1054 throw new OCPPError(
1055 ErrorType.GENERIC_ERROR,
1056 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1057 uploadResponse?.code && '|' + uploadResponse?.code.toString()
1058 }`,
1059 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1060 );
1061 }
1062 throw new OCPPError(
1063 ErrorType.GENERIC_ERROR,
1064 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1065 uploadResponse?.code && '|' + uploadResponse?.code.toString()
1066 }`,
1067 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
1068 );
1069 } catch (error) {
1070 await chargingStation.ocppRequestService.requestHandler<
1071 DiagnosticsStatusNotificationRequest,
1072 DiagnosticsStatusNotificationResponse
1073 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1074 status: OCPP16DiagnosticsStatus.UploadFailed,
1075 });
1076 if (ftpClient) {
1077 ftpClient.close();
1078 }
1079 return this.handleIncomingRequestError(
1080 chargingStation,
1081 OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
1082 error as Error,
1083 { errorResponse: Constants.OCPP_RESPONSE_EMPTY }
1084 );
1085 }
1086 } else {
1087 logger.error(
1088 `${chargingStation.logPrefix()} Unsupported protocol ${
1089 uri.protocol
1090 } to transfer the diagnostic logs archive`
1091 );
1092 await chargingStation.ocppRequestService.requestHandler<
1093 DiagnosticsStatusNotificationRequest,
1094 DiagnosticsStatusNotificationResponse
1095 >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, {
1096 status: OCPP16DiagnosticsStatus.UploadFailed,
1097 });
1098 return Constants.OCPP_RESPONSE_EMPTY;
1099 }
1100 }
1101
1102 private handleRequestTriggerMessage(
1103 chargingStation: ChargingStation,
1104 commandPayload: OCPP16TriggerMessageRequest
1105 ): OCPP16TriggerMessageResponse {
1106 if (
1107 !OCPP16ServiceUtils.checkFeatureProfile(
1108 chargingStation,
1109 OCPP16SupportedFeatureProfiles.RemoteTrigger,
1110 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
1111 )
1112 ) {
1113 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
1114 }
1115 // TODO: factor out the check on connector id
1116 if (commandPayload?.connectorId < 0) {
1117 logger.warn(
1118 `${chargingStation.logPrefix()} ${
1119 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE
1120 } incoming request received with invalid connectorId ${commandPayload.connectorId}`
1121 );
1122 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED;
1123 }
1124 try {
1125 switch (commandPayload.requestedMessage) {
1126 case MessageTrigger.BootNotification:
1127 setTimeout(() => {
1128 chargingStation.ocppRequestService
1129 .requestHandler<OCPP16BootNotificationRequest, OCPP16BootNotificationResponse>(
1130 chargingStation,
1131 OCPP16RequestCommand.BOOT_NOTIFICATION,
1132 chargingStation.bootNotificationRequest,
1133 { skipBufferingOnError: true, triggerMessage: true }
1134 )
1135 .then((response) => {
1136 chargingStation.bootNotificationResponse = response;
1137 })
1138 .catch(() => {
1139 /* This is intentional */
1140 });
1141 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1142 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
1143 case MessageTrigger.Heartbeat:
1144 setTimeout(() => {
1145 chargingStation.ocppRequestService
1146 .requestHandler<OCPP16HeartbeatRequest, OCPP16HeartbeatResponse>(
1147 chargingStation,
1148 OCPP16RequestCommand.HEARTBEAT,
1149 null,
1150 {
1151 triggerMessage: true,
1152 }
1153 )
1154 .catch(() => {
1155 /* This is intentional */
1156 });
1157 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1158 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
1159 case MessageTrigger.StatusNotification:
1160 setTimeout(() => {
1161 if (commandPayload?.connectorId) {
1162 chargingStation.ocppRequestService
1163 .requestHandler<OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse>(
1164 chargingStation,
1165 OCPP16RequestCommand.STATUS_NOTIFICATION,
1166 {
1167 connectorId: commandPayload.connectorId,
1168 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1169 status: chargingStation.getConnectorStatus(commandPayload.connectorId).status,
1170 },
1171 {
1172 triggerMessage: true,
1173 }
1174 )
1175 .catch(() => {
1176 /* This is intentional */
1177 });
1178 } else {
1179 for (const connectorId of chargingStation.connectors.keys()) {
1180 chargingStation.ocppRequestService
1181 .requestHandler<
1182 OCPP16StatusNotificationRequest,
1183 OCPP16StatusNotificationResponse
1184 >(
1185 chargingStation,
1186 OCPP16RequestCommand.STATUS_NOTIFICATION,
1187 {
1188 connectorId,
1189 errorCode: OCPP16ChargePointErrorCode.NO_ERROR,
1190 status: chargingStation.getConnectorStatus(connectorId).status,
1191 },
1192 {
1193 triggerMessage: true,
1194 }
1195 )
1196 .catch(() => {
1197 /* This is intentional */
1198 });
1199 }
1200 }
1201 }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
1202 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
1203 default:
1204 return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
1205 }
1206 } catch (error) {
1207 return this.handleIncomingRequestError(
1208 chargingStation,
1209 OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
1210 error as Error,
1211 { errorResponse: Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED }
1212 );
1213 }
1214 }
1215 }