1 // Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
3 import fs from
'node:fs';
4 import path from
'node:path';
5 import { URL
, fileURLToPath
} from
'node:url';
7 import type { JSONSchemaType
} from
'ajv';
8 import { Client
, type FTPResponse
} from
'basic-ftp';
11 import { OCPP16Constants
} from
'./OCPP16Constants';
12 import { OCPP16ServiceUtils
} from
'./OCPP16ServiceUtils';
15 ChargingStationConfigurationUtils
,
17 } from
'../../../charging-station';
18 import { OCPPError
} from
'../../../exception';
20 type ChangeAvailabilityRequest
,
21 type ChangeAvailabilityResponse
,
22 type ChangeConfigurationRequest
,
23 type ChangeConfigurationResponse
,
24 type ClearChargingProfileRequest
,
25 type ClearChargingProfileResponse
,
30 type GetConfigurationRequest
,
31 type GetConfigurationResponse
,
32 type GetDiagnosticsRequest
,
33 type GetDiagnosticsResponse
,
34 type IncomingRequestHandler
,
37 OCPP16AuthorizationStatus
,
38 type OCPP16AuthorizeRequest
,
39 type OCPP16AuthorizeResponse
,
40 OCPP16AvailabilityType
,
41 type OCPP16BootNotificationRequest
,
42 type OCPP16BootNotificationResponse
,
43 OCPP16ChargePointErrorCode
,
44 OCPP16ChargePointStatus
,
45 type OCPP16ChargingProfile
,
46 OCPP16ChargingProfilePurposeType
,
47 type OCPP16ChargingSchedule
,
48 type OCPP16ClearCacheRequest
,
49 type OCPP16DataTransferRequest
,
50 type OCPP16DataTransferResponse
,
51 OCPP16DataTransferStatus
,
52 OCPP16DataTransferVendorId
,
53 OCPP16DiagnosticsStatus
,
54 type OCPP16DiagnosticsStatusNotificationRequest
,
55 type OCPP16DiagnosticsStatusNotificationResponse
,
57 type OCPP16FirmwareStatusNotificationRequest
,
58 type OCPP16FirmwareStatusNotificationResponse
,
59 type OCPP16GetCompositeScheduleRequest
,
60 type OCPP16GetCompositeScheduleResponse
,
61 type OCPP16HeartbeatRequest
,
62 type OCPP16HeartbeatResponse
,
63 OCPP16IncomingRequestCommand
,
66 OCPP16StandardParametersKey
,
67 type OCPP16StartTransactionRequest
,
68 type OCPP16StartTransactionResponse
,
69 type OCPP16StatusNotificationRequest
,
70 type OCPP16StatusNotificationResponse
,
71 OCPP16StopTransactionReason
,
72 OCPP16SupportedFeatureProfiles
,
73 type OCPP16TriggerMessageRequest
,
74 type OCPP16TriggerMessageResponse
,
75 type OCPP16UpdateFirmwareRequest
,
76 type OCPP16UpdateFirmwareResponse
,
77 type OCPPConfigurationKey
,
79 type RemoteStartTransactionRequest
,
80 type RemoteStopTransactionRequest
,
82 type SetChargingProfileRequest
,
83 type SetChargingProfileResponse
,
84 type UnlockConnectorRequest
,
85 type UnlockConnectorResponse
,
86 } from
'../../../types';
87 import { Constants
, Utils
, logger
} from
'../../../utils';
88 import { OCPPIncomingRequestService
} from
'../OCPPIncomingRequestService';
90 const moduleName
= 'OCPP16IncomingRequestService';
92 export class OCPP16IncomingRequestService
extends OCPPIncomingRequestService
{
93 protected jsonSchemas
: Map
<OCPP16IncomingRequestCommand
, JSONSchemaType
<JsonObject
>>;
94 private incomingRequestHandlers
: Map
<OCPP16IncomingRequestCommand
, IncomingRequestHandler
>;
96 public constructor() {
97 // if (new.target?.name === moduleName) {
98 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
100 super(OCPPVersion
.VERSION_16
);
101 this.incomingRequestHandlers
= new Map
<OCPP16IncomingRequestCommand
, IncomingRequestHandler
>([
102 [OCPP16IncomingRequestCommand
.RESET
, this.handleRequestReset
.bind(this)],
103 [OCPP16IncomingRequestCommand
.CLEAR_CACHE
, this.handleRequestClearCache
.bind(this)],
104 [OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
, this.handleRequestUnlockConnector
.bind(this)],
106 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
107 this.handleRequestGetConfiguration
.bind(this),
110 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
111 this.handleRequestChangeConfiguration
.bind(this),
114 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
115 this.handleRequestGetCompositeSchedule
.bind(this),
118 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
119 this.handleRequestSetChargingProfile
.bind(this),
122 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
123 this.handleRequestClearChargingProfile
.bind(this),
126 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
127 this.handleRequestChangeAvailability
.bind(this),
130 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
131 this.handleRequestRemoteStartTransaction
.bind(this),
134 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
135 this.handleRequestRemoteStopTransaction
.bind(this),
137 [OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
, this.handleRequestGetDiagnostics
.bind(this)],
138 [OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
, this.handleRequestTriggerMessage
.bind(this)],
139 [OCPP16IncomingRequestCommand
.DATA_TRANSFER
, this.handleRequestDataTransfer
.bind(this)],
140 [OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
, this.handleRequestUpdateFirmware
.bind(this)],
142 this.jsonSchemas
= new Map
<OCPP16IncomingRequestCommand
, JSONSchemaType
<JsonObject
>>([
144 OCPP16IncomingRequestCommand
.RESET
,
145 OCPP16ServiceUtils
.parseJsonSchemaFile
<ResetRequest
>(
146 '../../../assets/json-schemas/ocpp/1.6/Reset.json',
152 OCPP16IncomingRequestCommand
.CLEAR_CACHE
,
153 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ClearCacheRequest
>(
154 '../../../assets/json-schemas/ocpp/1.6/ClearCache.json',
160 OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
,
161 OCPP16ServiceUtils
.parseJsonSchemaFile
<UnlockConnectorRequest
>(
162 '../../../assets/json-schemas/ocpp/1.6/UnlockConnector.json',
168 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
169 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetConfigurationRequest
>(
170 '../../../assets/json-schemas/ocpp/1.6/GetConfiguration.json',
176 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
177 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeConfigurationRequest
>(
178 '../../../assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
184 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
185 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetDiagnosticsRequest
>(
186 '../../../assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
192 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
193 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16GetCompositeScheduleRequest
>(
194 '../../../assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
200 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
201 OCPP16ServiceUtils
.parseJsonSchemaFile
<SetChargingProfileRequest
>(
202 '../../../assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
208 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
209 OCPP16ServiceUtils
.parseJsonSchemaFile
<ClearChargingProfileRequest
>(
210 '../../../assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
216 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
217 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeAvailabilityRequest
>(
218 '../../../assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
224 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
225 OCPP16ServiceUtils
.parseJsonSchemaFile
<RemoteStartTransactionRequest
>(
226 '../../../assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
232 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
233 OCPP16ServiceUtils
.parseJsonSchemaFile
<RemoteStopTransactionRequest
>(
234 '../../../assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
240 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
241 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16TriggerMessageRequest
>(
242 '../../../assets/json-schemas/ocpp/1.6/TriggerMessage.json',
248 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
249 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferRequest
>(
250 '../../../assets/json-schemas/ocpp/1.6/DataTransfer.json',
256 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
,
257 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16UpdateFirmwareRequest
>(
258 '../../../assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
264 this.validatePayload
= this.validatePayload
.bind(this) as (
265 chargingStation
: ChargingStation
,
266 commandName
: OCPP16IncomingRequestCommand
,
267 commandPayload
: JsonType
271 public async incomingRequestHandler(
272 chargingStation
: ChargingStation
,
274 commandName
: OCPP16IncomingRequestCommand
,
275 commandPayload
: JsonType
277 let response
: JsonType
;
279 chargingStation
.getOcppStrictCompliance() === true &&
280 chargingStation
.inPendingState() === true &&
281 (commandName
=== OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
||
282 commandName
=== OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
)
285 ErrorType
.SECURITY_ERROR
,
286 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
290 )} while the charging station is in pending state on the central server`,
296 chargingStation
.isRegistered() === true ||
297 (chargingStation
.getOcppStrictCompliance() === false &&
298 chargingStation
.inUnknownState() === true)
301 this.incomingRequestHandlers
.has(commandName
) === true &&
302 OCPP16ServiceUtils
.isIncomingRequestCommandSupported(chargingStation
, commandName
) === true
305 this.validatePayload(chargingStation
, commandName
, commandPayload
);
306 // Call the method to build the response
307 response
= await this.incomingRequestHandlers
.get(commandName
)(
314 `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
322 ErrorType
.NOT_IMPLEMENTED
,
323 `${commandName} is not implemented to handle request PDU ${JSON.stringify(
334 ErrorType
.SECURITY_ERROR
,
335 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
339 )} while the charging station is not registered on the central server.`,
344 // Send the built response
345 await chargingStation
.ocppRequestService
.sendResponse(
353 private validatePayload(
354 chargingStation
: ChargingStation
,
355 commandName
: OCPP16IncomingRequestCommand
,
356 commandPayload
: JsonType
358 if (this.jsonSchemas
.has(commandName
) === true) {
359 return this.validateIncomingRequestPayload(
362 this.jsonSchemas
.get(commandName
),
367 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
372 // Simulate charging station restart
373 private handleRequestReset(
374 chargingStation
: ChargingStation
,
375 commandPayload
: ResetRequest
377 this.runInAsyncScope(
378 chargingStation
.reset
.bind(chargingStation
) as (
379 this: ChargingStation
,
383 `${commandPayload.type}Reset` as OCPP16StopTransactionReason
384 ).catch(Constants
.EMPTY_FUNCTION
);
386 `${chargingStation.logPrefix()} ${
388 } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
389 chargingStation.stationInfo.resetTime
392 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
395 private async handleRequestUnlockConnector(
396 chargingStation
: ChargingStation
,
397 commandPayload
: UnlockConnectorRequest
398 ): Promise
<UnlockConnectorResponse
> {
399 const connectorId
= commandPayload
.connectorId
;
400 if (chargingStation
.hasConnector(connectorId
) === false) {
402 `${chargingStation.logPrefix()} Trying to unlock a non existing connector id ${connectorId.toString()}`
404 return OCPP16Constants
.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED
;
406 if (connectorId
=== 0) {
408 `${chargingStation.logPrefix()} Trying to unlock connector id ${connectorId.toString()}`
410 return OCPP16Constants
.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED
;
412 if (chargingStation
.getConnectorStatus(connectorId
)?.transactionStarted
=== true) {
413 const stopResponse
= await chargingStation
.stopTransactionOnConnector(
415 OCPP16StopTransactionReason
.UNLOCK_COMMAND
417 if (stopResponse
.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
418 return OCPP16Constants
.OCPP_RESPONSE_UNLOCKED
;
420 return OCPP16Constants
.OCPP_RESPONSE_UNLOCK_FAILED
;
422 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
425 OCPP16ChargePointStatus
.Available
427 return OCPP16Constants
.OCPP_RESPONSE_UNLOCKED
;
430 private handleRequestGetConfiguration(
431 chargingStation
: ChargingStation
,
432 commandPayload
: GetConfigurationRequest
433 ): GetConfigurationResponse
{
434 const configurationKey
: OCPPConfigurationKey
[] = [];
435 const unknownKey
: string[] = [];
436 if (Utils
.isUndefined(commandPayload
.key
) === true) {
437 for (const configuration
of chargingStation
.ocppConfiguration
.configurationKey
) {
438 if (Utils
.isUndefined(configuration
.visible
) === true) {
439 configuration
.visible
= true;
441 if (configuration
.visible
=== false) {
444 configurationKey
.push({
445 key
: configuration
.key
,
446 readonly: configuration
.readonly,
447 value
: configuration
.value
,
450 } else if (Utils
.isNotEmptyArray(commandPayload
.key
) === true) {
451 for (const key
of commandPayload
.key
) {
452 const keyFound
= ChargingStationConfigurationUtils
.getConfigurationKey(
458 if (Utils
.isUndefined(keyFound
.visible
) === true) {
459 keyFound
.visible
= true;
461 if (keyFound
.visible
=== false) {
464 configurationKey
.push({
466 readonly: keyFound
.readonly,
467 value
: keyFound
.value
,
470 unknownKey
.push(key
);
480 private handleRequestChangeConfiguration(
481 chargingStation
: ChargingStation
,
482 commandPayload
: ChangeConfigurationRequest
483 ): ChangeConfigurationResponse
{
484 const keyToChange
= ChargingStationConfigurationUtils
.getConfigurationKey(
490 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED
;
491 } else if (keyToChange
?.readonly === true) {
492 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_REJECTED
;
493 } else if (keyToChange
?.readonly === false) {
494 let valueChanged
= false;
495 if (keyToChange
.value
!== commandPayload
.value
) {
496 ChargingStationConfigurationUtils
.setConfigurationKeyValue(
499 commandPayload
.value
,
504 let triggerHeartbeatRestart
= false;
505 if (keyToChange
.key
=== OCPP16StandardParametersKey
.HeartBeatInterval
&& valueChanged
) {
506 ChargingStationConfigurationUtils
.setConfigurationKeyValue(
508 OCPP16StandardParametersKey
.HeartbeatInterval
,
511 triggerHeartbeatRestart
= true;
513 if (keyToChange
.key
=== OCPP16StandardParametersKey
.HeartbeatInterval
&& valueChanged
) {
514 ChargingStationConfigurationUtils
.setConfigurationKeyValue(
516 OCPP16StandardParametersKey
.HeartBeatInterval
,
519 triggerHeartbeatRestart
= true;
521 if (triggerHeartbeatRestart
) {
522 chargingStation
.restartHeartbeat();
524 if (keyToChange
.key
=== OCPP16StandardParametersKey
.WebSocketPingInterval
&& valueChanged
) {
525 chargingStation
.restartWebSocketPing();
527 if (keyToChange
.reboot
) {
528 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED
;
530 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_ACCEPTED
;
534 private handleRequestSetChargingProfile(
535 chargingStation
: ChargingStation
,
536 commandPayload
: SetChargingProfileRequest
537 ): SetChargingProfileResponse
{
539 OCPP16ServiceUtils
.checkFeatureProfile(
541 OCPP16SupportedFeatureProfiles
.SmartCharging
,
542 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
545 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED
;
547 if (chargingStation
.hasConnector(commandPayload
.connectorId
) === false) {
549 `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector id ${
550 commandPayload.connectorId
553 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED
;
556 commandPayload
.csChargingProfiles
.chargingProfilePurpose
===
557 OCPP16ChargingProfilePurposeType
.CHARGE_POINT_MAX_PROFILE
&&
558 commandPayload
.connectorId
!== 0
560 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED
;
563 commandPayload
.csChargingProfiles
.chargingProfilePurpose
===
564 OCPP16ChargingProfilePurposeType
.TX_PROFILE
&&
565 (commandPayload
.connectorId
=== 0 ||
566 chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.transactionStarted
===
570 `${chargingStation.logPrefix()} Trying to set transaction charging profile(s) on connector ${
571 commandPayload.connectorId
572 } without a started transaction`
574 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED
;
576 OCPP16ServiceUtils
.setChargingProfile(
578 commandPayload
.connectorId
,
579 commandPayload
.csChargingProfiles
582 `${chargingStation.logPrefix()} Charging profile(s) set on connector id ${
583 commandPayload.connectorId
585 commandPayload
.csChargingProfiles
587 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED
;
590 private handleRequestGetCompositeSchedule(
591 chargingStation
: ChargingStation
,
592 commandPayload
: OCPP16GetCompositeScheduleRequest
593 ): OCPP16GetCompositeScheduleResponse
{
595 OCPP16ServiceUtils
.checkFeatureProfile(
597 OCPP16SupportedFeatureProfiles
.SmartCharging
,
598 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
601 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
603 if (chargingStation
.hasConnector(commandPayload
.connectorId
) === false) {
605 `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector id ${
606 commandPayload.connectorId
609 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
613 chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.chargingProfiles
616 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
618 const startDate
= new Date();
619 const endDate
= new Date(startDate
.getTime() + commandPayload
.duration
* 1000);
620 let compositeSchedule
: OCPP16ChargingSchedule
;
621 for (const chargingProfile
of chargingStation
.getConnectorStatus(commandPayload
.connectorId
)
623 // FIXME: build the composite schedule including the local power limit, the stack level, the charging rate unit, etc.
625 chargingProfile
.chargingSchedule
?.startSchedule
>= startDate
&&
626 chargingProfile
.chargingSchedule
?.startSchedule
<= endDate
628 compositeSchedule
= chargingProfile
.chargingSchedule
;
633 status: GenericStatus
.Accepted
,
634 scheduleStart
: compositeSchedule
?.startSchedule
,
635 connectorId
: commandPayload
.connectorId
,
636 chargingSchedule
: compositeSchedule
,
640 private handleRequestClearChargingProfile(
641 chargingStation
: ChargingStation
,
642 commandPayload
: ClearChargingProfileRequest
643 ): ClearChargingProfileResponse
{
645 OCPP16ServiceUtils
.checkFeatureProfile(
647 OCPP16SupportedFeatureProfiles
.SmartCharging
,
648 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
651 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
;
653 if (chargingStation
.hasConnector(commandPayload
.connectorId
) === false) {
655 `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${
656 commandPayload.connectorId
659 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
;
662 !Utils
.isNullOrUndefined(commandPayload
.connectorId
) &&
663 Utils
.isNotEmptyArray(
664 chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.chargingProfiles
667 chargingStation
.getConnectorStatus(commandPayload
.connectorId
).chargingProfiles
= [];
669 `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
670 commandPayload.connectorId
673 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED
;
675 if (Utils
.isNullOrUndefined(commandPayload
.connectorId
)) {
676 let clearedCP
= false;
677 const clearChargingProfiles
= (connectorStatus
: ConnectorStatus
) => {
678 if (Utils
.isNotEmptyArray(connectorStatus
?.chargingProfiles
)) {
679 connectorStatus
?.chargingProfiles
?.forEach(
680 (chargingProfile
: OCPP16ChargingProfile
, index
: number) => {
681 let clearCurrentCP
= false;
682 if (chargingProfile
.chargingProfileId
=== commandPayload
.id
) {
683 clearCurrentCP
= true;
686 !commandPayload
.chargingProfilePurpose
&&
687 chargingProfile
.stackLevel
=== commandPayload
.stackLevel
689 clearCurrentCP
= true;
692 !chargingProfile
.stackLevel
&&
693 chargingProfile
.chargingProfilePurpose
=== commandPayload
.chargingProfilePurpose
695 clearCurrentCP
= true;
698 chargingProfile
.stackLevel
=== commandPayload
.stackLevel
&&
699 chargingProfile
.chargingProfilePurpose
=== commandPayload
.chargingProfilePurpose
701 clearCurrentCP
= true;
703 if (clearCurrentCP
) {
704 connectorStatus
?.chargingProfiles
?.splice(index
, 1);
706 `${chargingStation.logPrefix()} Matching charging profile(s) cleared: %j`,
715 if (chargingStation
.hasEvses
) {
716 for (const evseStatus
of chargingStation
.evses
.values()) {
717 for (const connectorStatus
of evseStatus
.connectors
.values()) {
718 clearChargingProfiles(connectorStatus
);
722 for (const connectorId
of chargingStation
.connectors
.keys()) {
723 clearChargingProfiles(chargingStation
.getConnectorStatus(connectorId
));
727 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED
;
730 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
;
733 private async handleRequestChangeAvailability(
734 chargingStation
: ChargingStation
,
735 commandPayload
: ChangeAvailabilityRequest
736 ): Promise
<ChangeAvailabilityResponse
> {
737 const connectorId
: number = commandPayload
.connectorId
;
738 if (chargingStation
.hasConnector(connectorId
) === false) {
740 `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector id ${connectorId.toString()}`
742 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_REJECTED
;
744 const chargePointStatus
: OCPP16ChargePointStatus
=
745 commandPayload
.type === OCPP16AvailabilityType
.Operative
746 ? OCPP16ChargePointStatus
.Available
747 : OCPP16ChargePointStatus
.Unavailable
;
748 if (connectorId
=== 0) {
749 let response
: ChangeAvailabilityResponse
=
750 OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
;
751 const changeAvailability
= async (id
: number, connectorStatus
: ConnectorStatus
) => {
752 if (connectorStatus
?.transactionStarted
=== true) {
753 response
= OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
;
755 connectorStatus
.availability
= commandPayload
.type;
756 if (response
=== OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
) {
757 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
764 if (chargingStation
.hasEvses
) {
765 for (const evseStatus
of chargingStation
.evses
.values()) {
766 for (const [id
, connectorStatus
] of evseStatus
.connectors
) {
767 await changeAvailability(id
, connectorStatus
);
771 for (const id
of chargingStation
.connectors
.keys()) {
772 await changeAvailability(id
, chargingStation
.getConnectorStatus(id
));
778 (chargingStation
.isChargingStationAvailable() === true ||
779 (chargingStation
.isChargingStationAvailable() === false &&
780 commandPayload
.type === OCPP16AvailabilityType
.Inoperative
))
782 if (chargingStation
.getConnectorStatus(connectorId
)?.transactionStarted
=== true) {
783 chargingStation
.getConnectorStatus(connectorId
).availability
= commandPayload
.type;
784 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
;
786 chargingStation
.getConnectorStatus(connectorId
).availability
= commandPayload
.type;
787 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
792 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
;
794 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_REJECTED
;
797 private async handleRequestRemoteStartTransaction(
798 chargingStation
: ChargingStation
,
799 commandPayload
: RemoteStartTransactionRequest
800 ): Promise
<GenericResponse
> {
801 const transactionConnectorId
= commandPayload
.connectorId
;
802 if (chargingStation
.hasConnector(transactionConnectorId
) === false) {
803 return this.notifyRemoteStartTransactionRejected(
805 transactionConnectorId
,
810 chargingStation
.isChargingStationAvailable() === false ||
811 chargingStation
.isConnectorAvailable(transactionConnectorId
) === false
813 return this.notifyRemoteStartTransactionRejected(
815 transactionConnectorId
,
819 const remoteStartTransactionLogMsg
= `${chargingStation.logPrefix()} Transaction remotely STARTED on ${
820 chargingStation.stationInfo.chargingStationId
821 }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`;
822 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
824 transactionConnectorId
,
825 OCPP16ChargePointStatus
.Preparing
827 const connectorStatus
= chargingStation
.getConnectorStatus(transactionConnectorId
);
828 // Check if authorized
829 if (chargingStation
.getAuthorizeRemoteTxRequests() === true) {
830 let authorized
= false;
832 chargingStation
.getLocalAuthListEnabled() === true &&
833 chargingStation
.hasIdTags() === true &&
834 Utils
.isNotEmptyString(
835 chargingStation
.idTagsCache
836 .getIdTags(ChargingStationUtils
.getIdTagsFile(chargingStation
.stationInfo
))
837 ?.find((idTag
) => idTag
=== commandPayload
.idTag
)
840 connectorStatus
.localAuthorizeIdTag
= commandPayload
.idTag
;
841 connectorStatus
.idTagLocalAuthorized
= true;
843 } else if (chargingStation
.getMustAuthorizeAtRemoteStart() === true) {
844 connectorStatus
.authorizeIdTag
= commandPayload
.idTag
;
845 const authorizeResponse
: OCPP16AuthorizeResponse
=
846 await chargingStation
.ocppRequestService
.requestHandler
<
847 OCPP16AuthorizeRequest
,
848 OCPP16AuthorizeResponse
849 >(chargingStation
, OCPP16RequestCommand
.AUTHORIZE
, {
850 idTag
: commandPayload
.idTag
,
852 if (authorizeResponse
?.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
857 `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
860 if (authorized
=== true) {
861 // Authorization successful, start transaction
863 this.setRemoteStartTransactionChargingProfile(
865 transactionConnectorId
,
866 commandPayload
.chargingProfile
869 connectorStatus
.transactionRemoteStarted
= true;
872 await chargingStation
.ocppRequestService
.requestHandler
<
873 OCPP16StartTransactionRequest
,
874 OCPP16StartTransactionResponse
875 >(chargingStation
, OCPP16RequestCommand
.START_TRANSACTION
, {
876 connectorId
: transactionConnectorId
,
877 idTag
: commandPayload
.idTag
,
879 ).idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
881 logger
.debug(remoteStartTransactionLogMsg
);
882 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
884 return this.notifyRemoteStartTransactionRejected(
886 transactionConnectorId
,
890 return this.notifyRemoteStartTransactionRejected(
892 transactionConnectorId
,
896 return this.notifyRemoteStartTransactionRejected(
898 transactionConnectorId
,
902 // No authorization check required, start transaction
904 this.setRemoteStartTransactionChargingProfile(
906 transactionConnectorId
,
907 commandPayload
.chargingProfile
910 connectorStatus
.transactionRemoteStarted
= true;
913 await chargingStation
.ocppRequestService
.requestHandler
<
914 OCPP16StartTransactionRequest
,
915 OCPP16StartTransactionResponse
916 >(chargingStation
, OCPP16RequestCommand
.START_TRANSACTION
, {
917 connectorId
: transactionConnectorId
,
918 idTag
: commandPayload
.idTag
,
920 ).idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
922 logger
.debug(remoteStartTransactionLogMsg
);
923 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
925 return this.notifyRemoteStartTransactionRejected(
927 transactionConnectorId
,
931 return this.notifyRemoteStartTransactionRejected(
933 transactionConnectorId
,
938 private async notifyRemoteStartTransactionRejected(
939 chargingStation
: ChargingStation
,
942 ): Promise
<GenericResponse
> {
944 chargingStation
.getConnectorStatus(connectorId
)?.status !== OCPP16ChargePointStatus
.Available
946 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
949 OCPP16ChargePointStatus
.Available
953 `${chargingStation.logPrefix()} Remote starting transaction REJECTED on connector id ${connectorId.toString()}, idTag '${idTag}', availability '${
954 chargingStation.getConnectorStatus(connectorId)?.availability
955 }', status '${chargingStation.getConnectorStatus(connectorId)?.status}'`
957 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
960 private setRemoteStartTransactionChargingProfile(
961 chargingStation
: ChargingStation
,
963 cp
: OCPP16ChargingProfile
965 if (cp
&& cp
.chargingProfilePurpose
=== OCPP16ChargingProfilePurposeType
.TX_PROFILE
) {
966 OCPP16ServiceUtils
.setChargingProfile(chargingStation
, connectorId
, cp
);
968 `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}: %j`,
972 } else if (cp
&& cp
.chargingProfilePurpose
!== OCPP16ChargingProfilePurposeType
.TX_PROFILE
) {
974 `${chargingStation.logPrefix()} Not allowed to set ${
975 cp.chargingProfilePurpose
976 } charging profile(s) at remote start transaction`
984 private async handleRequestRemoteStopTransaction(
985 chargingStation
: ChargingStation
,
986 commandPayload
: RemoteStopTransactionRequest
987 ): Promise
<GenericResponse
> {
988 const transactionId
= commandPayload
.transactionId
;
989 const remoteStopTransaction
= async (connectorId
: number): Promise
<GenericResponse
> => {
990 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
993 OCPP16ChargePointStatus
.Finishing
995 const stopResponse
= await chargingStation
.stopTransactionOnConnector(
997 OCPP16StopTransactionReason
.REMOTE
999 if (stopResponse
.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
1000 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
1002 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
1004 if (chargingStation
.hasEvses
) {
1005 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
1007 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1008 if (connectorStatus
.transactionId
=== transactionId
) {
1009 return remoteStopTransaction(connectorId
);
1015 for (const connectorId
of chargingStation
.connectors
.keys()) {
1018 chargingStation
.getConnectorStatus(connectorId
)?.transactionId
=== transactionId
1020 return remoteStopTransaction(connectorId
);
1025 `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction with id: ${transactionId.toString()}`
1027 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
1030 private handleRequestUpdateFirmware(
1031 chargingStation
: ChargingStation
,
1032 commandPayload
: OCPP16UpdateFirmwareRequest
1033 ): OCPP16UpdateFirmwareResponse
{
1035 OCPP16ServiceUtils
.checkFeatureProfile(
1037 OCPP16SupportedFeatureProfiles
.FirmwareManagement
,
1038 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
1042 `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: feature profile not supported`
1044 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1047 !Utils
.isNullOrUndefined(chargingStation
.stationInfo
.firmwareStatus
) &&
1048 chargingStation
.stationInfo
.firmwareStatus
!== OCPP16FirmwareStatus
.Installed
1051 `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: firmware update is already in progress`
1053 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1055 const retrieveDate
= Utils
.convertToDate(commandPayload
.retrieveDate
);
1056 const now
= Date.now();
1057 if (retrieveDate
?.getTime() <= now
) {
1058 this.runInAsyncScope(
1059 this.updateFirmwareSimulation
.bind(this) as (
1060 this: OCPP16IncomingRequestService
,
1065 ).catch(Constants
.EMPTY_FUNCTION
);
1068 this.updateFirmwareSimulation(chargingStation
).catch(Constants
.EMPTY_FUNCTION
);
1069 }, retrieveDate
?.getTime() - now
);
1071 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1074 private async updateFirmwareSimulation(
1075 chargingStation
: ChargingStation
,
1080 ChargingStationUtils
.checkChargingStation(chargingStation
, chargingStation
.logPrefix()) ===
1085 if (chargingStation
.hasEvses
) {
1086 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
1088 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1089 if (connectorStatus
?.transactionStarted
=== false) {
1090 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1093 OCPP16ChargePointStatus
.Unavailable
1100 for (const connectorId
of chargingStation
.connectors
.keys()) {
1103 chargingStation
.getConnectorStatus(connectorId
)?.transactionStarted
=== false
1105 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1108 OCPP16ChargePointStatus
.Unavailable
1113 await chargingStation
.ocppRequestService
.requestHandler
<
1114 OCPP16FirmwareStatusNotificationRequest
,
1115 OCPP16FirmwareStatusNotificationResponse
1116 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1117 status: OCPP16FirmwareStatus
.Downloading
,
1119 chargingStation
.stationInfo
.firmwareStatus
= OCPP16FirmwareStatus
.Downloading
;
1121 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
===
1122 OCPP16FirmwareStatus
.DownloadFailed
1124 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1125 await chargingStation
.ocppRequestService
.requestHandler
<
1126 OCPP16FirmwareStatusNotificationRequest
,
1127 OCPP16FirmwareStatusNotificationResponse
1128 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1129 status: chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
,
1131 chargingStation
.stationInfo
.firmwareStatus
=
1132 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
;
1135 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1136 await chargingStation
.ocppRequestService
.requestHandler
<
1137 OCPP16FirmwareStatusNotificationRequest
,
1138 OCPP16FirmwareStatusNotificationResponse
1139 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1140 status: OCPP16FirmwareStatus
.Downloaded
,
1142 chargingStation
.stationInfo
.firmwareStatus
= OCPP16FirmwareStatus
.Downloaded
;
1143 let wasTransactionsStarted
= false;
1144 let transactionsStarted
: boolean;
1146 const runningTransactions
= chargingStation
.getNumberOfRunningTransactions();
1147 if (runningTransactions
> 0) {
1148 const waitTime
= 15 * 1000;
1150 `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${runningTransactions} transaction(s) in progress, waiting ${
1152 } seconds before continuing firmware update simulation`
1154 await Utils
.sleep(waitTime
);
1155 transactionsStarted
= true;
1156 wasTransactionsStarted
= true;
1158 if (chargingStation
.hasEvses
) {
1159 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
1161 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1162 if (connectorStatus
?.status !== OCPP16ChargePointStatus
.Unavailable
) {
1163 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1166 OCPP16ChargePointStatus
.Unavailable
1173 for (const connectorId
of chargingStation
.connectors
.keys()) {
1176 chargingStation
.getConnectorStatus(connectorId
)?.status !==
1177 OCPP16ChargePointStatus
.Unavailable
1179 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1182 OCPP16ChargePointStatus
.Unavailable
1187 transactionsStarted
= false;
1189 } while (transactionsStarted
);
1190 !wasTransactionsStarted
&&
1191 (await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000));
1193 ChargingStationUtils
.checkChargingStation(chargingStation
, chargingStation
.logPrefix()) ===
1198 await chargingStation
.ocppRequestService
.requestHandler
<
1199 OCPP16FirmwareStatusNotificationRequest
,
1200 OCPP16FirmwareStatusNotificationResponse
1201 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1202 status: OCPP16FirmwareStatus
.Installing
,
1204 chargingStation
.stationInfo
.firmwareStatus
= OCPP16FirmwareStatus
.Installing
;
1206 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
===
1207 OCPP16FirmwareStatus
.InstallationFailed
1209 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1210 await chargingStation
.ocppRequestService
.requestHandler
<
1211 OCPP16FirmwareStatusNotificationRequest
,
1212 OCPP16FirmwareStatusNotificationResponse
1213 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1214 status: chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
,
1216 chargingStation
.stationInfo
.firmwareStatus
=
1217 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
;
1220 if (chargingStation
.stationInfo
?.firmwareUpgrade
?.reset
=== true) {
1221 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1222 await chargingStation
.reset(OCPP16StopTransactionReason
.REBOOT
);
1226 private async handleRequestGetDiagnostics(
1227 chargingStation
: ChargingStation
,
1228 commandPayload
: GetDiagnosticsRequest
1229 ): Promise
<GetDiagnosticsResponse
> {
1231 OCPP16ServiceUtils
.checkFeatureProfile(
1233 OCPP16SupportedFeatureProfiles
.FirmwareManagement
,
1234 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
1238 `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Cannot get diagnostics: feature profile not supported`
1240 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1242 const uri
= new URL(commandPayload
.location
);
1243 if (uri
.protocol
.startsWith('ftp:')) {
1244 let ftpClient
: Client
;
1247 .readdirSync(path
.resolve(path
.dirname(fileURLToPath(import.meta
.url
)), '../../../../'))
1248 .filter((file
) => file
.endsWith('.log'))
1249 .map((file
) => path
.join('./', file
));
1250 const diagnosticsArchive
= `${chargingStation.stationInfo.chargingStationId}_logs.tar.gz`;
1251 tar
.create({ gzip
: true }, logFiles
).pipe(fs
.createWriteStream(diagnosticsArchive
));
1252 ftpClient
= new Client();
1253 const accessResponse
= await ftpClient
.access({
1255 ...(Utils
.isNotEmptyString(uri
.port
) && { port
: Utils
.convertToInt(uri
.port
) }),
1256 ...(Utils
.isNotEmptyString(uri
.username
) && { user
: uri
.username
}),
1257 ...(Utils
.isNotEmptyString(uri
.password
) && { password
: uri
.password
}),
1259 let uploadResponse
: FTPResponse
;
1260 if (accessResponse
.code
=== 220) {
1261 ftpClient
.trackProgress((info
) => {
1263 `${chargingStation.logPrefix()} ${
1265 } bytes transferred from diagnostics archive ${info.name}`
1267 chargingStation
.ocppRequestService
1269 OCPP16DiagnosticsStatusNotificationRequest
,
1270 OCPP16DiagnosticsStatusNotificationResponse
1271 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1272 status: OCPP16DiagnosticsStatus
.Uploading
,
1276 `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Error while sending '${
1277 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION
1283 uploadResponse
= await ftpClient
.uploadFrom(
1285 path
.resolve(path
.dirname(fileURLToPath(import.meta
.url
)), '../../../../'),
1288 `${uri.pathname}${diagnosticsArchive}`
1290 if (uploadResponse
.code
=== 226) {
1291 await chargingStation
.ocppRequestService
.requestHandler
<
1292 OCPP16DiagnosticsStatusNotificationRequest
,
1293 OCPP16DiagnosticsStatusNotificationResponse
1294 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1295 status: OCPP16DiagnosticsStatus
.Uploaded
,
1300 return { fileName
: diagnosticsArchive
};
1302 throw new OCPPError(
1303 ErrorType
.GENERIC_ERROR
,
1304 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1305 uploadResponse?.code && `|${uploadResponse?.code.toString()}
`
1307 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
1310 throw new OCPPError(
1311 ErrorType
.GENERIC_ERROR
,
1312 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1313 uploadResponse?.code && `|${uploadResponse?.code.toString()}
`
1315 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
1318 await chargingStation
.ocppRequestService
.requestHandler
<
1319 OCPP16DiagnosticsStatusNotificationRequest
,
1320 OCPP16DiagnosticsStatusNotificationResponse
1321 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1322 status: OCPP16DiagnosticsStatus
.UploadFailed
,
1327 return this.handleIncomingRequestError(
1329 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
1331 { errorResponse
: OCPP16Constants
.OCPP_RESPONSE_EMPTY
}
1336 `${chargingStation.logPrefix()} Unsupported protocol ${
1338 } to transfer the diagnostic logs archive`
1340 await chargingStation
.ocppRequestService
.requestHandler
<
1341 OCPP16DiagnosticsStatusNotificationRequest
,
1342 OCPP16DiagnosticsStatusNotificationResponse
1343 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1344 status: OCPP16DiagnosticsStatus
.UploadFailed
,
1346 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1350 private handleRequestTriggerMessage(
1351 chargingStation
: ChargingStation
,
1352 commandPayload
: OCPP16TriggerMessageRequest
1353 ): OCPP16TriggerMessageResponse
{
1355 !OCPP16ServiceUtils
.checkFeatureProfile(
1357 OCPP16SupportedFeatureProfiles
.RemoteTrigger
,
1358 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
1360 !OCPP16ServiceUtils
.isMessageTriggerSupported(
1362 commandPayload
.requestedMessage
1365 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED
;
1368 !OCPP16ServiceUtils
.isConnectorIdValid(
1370 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
1371 commandPayload
.connectorId
1374 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED
;
1377 switch (commandPayload
.requestedMessage
) {
1378 case OCPP16MessageTrigger
.BootNotification
:
1380 chargingStation
.ocppRequestService
1381 .requestHandler
<OCPP16BootNotificationRequest
, OCPP16BootNotificationResponse
>(
1383 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
1384 chargingStation
.bootNotificationRequest
,
1385 { skipBufferingOnError
: true, triggerMessage
: true }
1387 .then((response
) => {
1388 chargingStation
.bootNotificationResponse
= response
;
1390 .catch(Constants
.EMPTY_FUNCTION
);
1391 }, OCPP16Constants
.OCPP_TRIGGER_MESSAGE_DELAY
);
1392 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
;
1393 case OCPP16MessageTrigger
.Heartbeat
:
1395 chargingStation
.ocppRequestService
1396 .requestHandler
<OCPP16HeartbeatRequest
, OCPP16HeartbeatResponse
>(
1398 OCPP16RequestCommand
.HEARTBEAT
,
1401 triggerMessage
: true,
1404 .catch(Constants
.EMPTY_FUNCTION
);
1405 }, OCPP16Constants
.OCPP_TRIGGER_MESSAGE_DELAY
);
1406 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
;
1407 case OCPP16MessageTrigger
.StatusNotification
:
1409 if (!Utils
.isNullOrUndefined(commandPayload
?.connectorId
)) {
1410 chargingStation
.ocppRequestService
1411 .requestHandler
<OCPP16StatusNotificationRequest
, OCPP16StatusNotificationResponse
>(
1413 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
1415 connectorId
: commandPayload
.connectorId
,
1416 errorCode
: OCPP16ChargePointErrorCode
.NO_ERROR
,
1417 status: chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.status,
1420 triggerMessage
: true,
1423 .catch(Constants
.EMPTY_FUNCTION
);
1425 // eslint-disable-next-line no-lonely-if
1426 if (chargingStation
.hasEvses
) {
1427 for (const evseStatus
of chargingStation
.evses
.values()) {
1428 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1429 chargingStation
.ocppRequestService
1431 OCPP16StatusNotificationRequest
,
1432 OCPP16StatusNotificationResponse
1435 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
1438 errorCode
: OCPP16ChargePointErrorCode
.NO_ERROR
,
1439 status: connectorStatus
.status,
1442 triggerMessage
: true,
1445 .catch(Constants
.EMPTY_FUNCTION
);
1449 for (const connectorId
of chargingStation
.connectors
.keys()) {
1450 chargingStation
.ocppRequestService
1452 OCPP16StatusNotificationRequest
,
1453 OCPP16StatusNotificationResponse
1456 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
1459 errorCode
: OCPP16ChargePointErrorCode
.NO_ERROR
,
1460 status: chargingStation
.getConnectorStatus(connectorId
)?.status,
1463 triggerMessage
: true,
1466 .catch(Constants
.EMPTY_FUNCTION
);
1470 }, OCPP16Constants
.OCPP_TRIGGER_MESSAGE_DELAY
);
1471 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
;
1473 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED
;
1476 return this.handleIncomingRequestError(
1478 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
1480 { errorResponse
: OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED
}
1485 private handleRequestDataTransfer(
1486 chargingStation
: ChargingStation
,
1487 commandPayload
: OCPP16DataTransferRequest
1488 ): OCPP16DataTransferResponse
{
1490 if (Object.values(OCPP16DataTransferVendorId
).includes(commandPayload
.vendorId
)) {
1492 status: OCPP16DataTransferStatus
.ACCEPTED
,
1496 status: OCPP16DataTransferStatus
.UNKNOWN_VENDOR_ID
,
1499 return this.handleIncomingRequestError(
1501 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
1503 { errorResponse
: OCPP16Constants
.OCPP_DATA_TRANSFER_RESPONSE_REJECTED
}