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