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