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