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