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 OCPP16DataTransferVendorId
,
52 OCPP16DiagnosticsStatus
,
53 type OCPP16DiagnosticsStatusNotificationRequest
,
54 type OCPP16DiagnosticsStatusNotificationResponse
,
56 type OCPP16FirmwareStatusNotificationRequest
,
57 type OCPP16FirmwareStatusNotificationResponse
,
58 type OCPP16GetCompositeScheduleRequest
,
59 type OCPP16GetCompositeScheduleResponse
,
60 type OCPP16HeartbeatRequest
,
61 type OCPP16HeartbeatResponse
,
62 OCPP16IncomingRequestCommand
,
65 OCPP16StandardParametersKey
,
66 type OCPP16StartTransactionRequest
,
67 type OCPP16StartTransactionResponse
,
68 type OCPP16StatusNotificationRequest
,
69 type OCPP16StatusNotificationResponse
,
70 OCPP16StopTransactionReason
,
71 OCPP16SupportedFeatureProfiles
,
72 type OCPP16TriggerMessageRequest
,
73 type OCPP16TriggerMessageResponse
,
74 type OCPP16UpdateFirmwareRequest
,
75 type OCPP16UpdateFirmwareResponse
,
76 type OCPPConfigurationKey
,
78 type RemoteStartTransactionRequest
,
79 type RemoteStopTransactionRequest
,
81 type SetChargingProfileRequest
,
82 type SetChargingProfileResponse
,
83 type UnlockConnectorRequest
,
84 type UnlockConnectorResponse
,
85 } from
'../../../types';
86 import { Constants
, Utils
, logger
} from
'../../../utils';
87 import { OCPPIncomingRequestService
} from
'../OCPPIncomingRequestService';
89 const moduleName
= 'OCPP16IncomingRequestService';
91 export class OCPP16IncomingRequestService
extends OCPPIncomingRequestService
{
92 protected jsonSchemas
: Map
<OCPP16IncomingRequestCommand
, JSONSchemaType
<JsonObject
>>;
93 private incomingRequestHandlers
: Map
<OCPP16IncomingRequestCommand
, IncomingRequestHandler
>;
95 public constructor() {
96 // if (new.target?.name === moduleName) {
97 // throw new TypeError(`Cannot construct ${new.target?.name} instances directly`);
99 super(OCPPVersion
.VERSION_16
);
100 this.incomingRequestHandlers
= new Map
<OCPP16IncomingRequestCommand
, IncomingRequestHandler
>([
101 [OCPP16IncomingRequestCommand
.RESET
, this.handleRequestReset
.bind(this)],
102 [OCPP16IncomingRequestCommand
.CLEAR_CACHE
, this.handleRequestClearCache
.bind(this)],
103 [OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
, this.handleRequestUnlockConnector
.bind(this)],
105 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
106 this.handleRequestGetConfiguration
.bind(this),
109 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
110 this.handleRequestChangeConfiguration
.bind(this),
113 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
114 this.handleRequestGetCompositeSchedule
.bind(this),
117 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
118 this.handleRequestSetChargingProfile
.bind(this),
121 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
122 this.handleRequestClearChargingProfile
.bind(this),
125 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
126 this.handleRequestChangeAvailability
.bind(this),
129 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
130 this.handleRequestRemoteStartTransaction
.bind(this),
133 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
134 this.handleRequestRemoteStopTransaction
.bind(this),
136 [OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
, this.handleRequestGetDiagnostics
.bind(this)],
137 [OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
, this.handleRequestTriggerMessage
.bind(this)],
138 [OCPP16IncomingRequestCommand
.DATA_TRANSFER
, this.handleRequestDataTransfer
.bind(this)],
139 [OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
, this.handleRequestUpdateFirmware
.bind(this)],
141 this.jsonSchemas
= new Map
<OCPP16IncomingRequestCommand
, JSONSchemaType
<JsonObject
>>([
143 OCPP16IncomingRequestCommand
.RESET
,
144 OCPP16ServiceUtils
.parseJsonSchemaFile
<ResetRequest
>(
145 'assets/json-schemas/ocpp/1.6/Reset.json',
151 OCPP16IncomingRequestCommand
.CLEAR_CACHE
,
152 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16ClearCacheRequest
>(
153 'assets/json-schemas/ocpp/1.6/ClearCache.json',
159 OCPP16IncomingRequestCommand
.UNLOCK_CONNECTOR
,
160 OCPP16ServiceUtils
.parseJsonSchemaFile
<UnlockConnectorRequest
>(
161 'assets/json-schemas/ocpp/1.6/UnlockConnector.json',
167 OCPP16IncomingRequestCommand
.GET_CONFIGURATION
,
168 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetConfigurationRequest
>(
169 'assets/json-schemas/ocpp/1.6/GetConfiguration.json',
175 OCPP16IncomingRequestCommand
.CHANGE_CONFIGURATION
,
176 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeConfigurationRequest
>(
177 'assets/json-schemas/ocpp/1.6/ChangeConfiguration.json',
183 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
184 OCPP16ServiceUtils
.parseJsonSchemaFile
<GetDiagnosticsRequest
>(
185 'assets/json-schemas/ocpp/1.6/GetDiagnostics.json',
191 OCPP16IncomingRequestCommand
.GET_COMPOSITE_SCHEDULE
,
192 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16GetCompositeScheduleRequest
>(
193 'assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json',
199 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
,
200 OCPP16ServiceUtils
.parseJsonSchemaFile
<SetChargingProfileRequest
>(
201 'assets/json-schemas/ocpp/1.6/SetChargingProfile.json',
207 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
,
208 OCPP16ServiceUtils
.parseJsonSchemaFile
<ClearChargingProfileRequest
>(
209 'assets/json-schemas/ocpp/1.6/ClearChargingProfile.json',
215 OCPP16IncomingRequestCommand
.CHANGE_AVAILABILITY
,
216 OCPP16ServiceUtils
.parseJsonSchemaFile
<ChangeAvailabilityRequest
>(
217 'assets/json-schemas/ocpp/1.6/ChangeAvailability.json',
223 OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
,
224 OCPP16ServiceUtils
.parseJsonSchemaFile
<RemoteStartTransactionRequest
>(
225 'assets/json-schemas/ocpp/1.6/RemoteStartTransaction.json',
231 OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
,
232 OCPP16ServiceUtils
.parseJsonSchemaFile
<RemoteStopTransactionRequest
>(
233 'assets/json-schemas/ocpp/1.6/RemoteStopTransaction.json',
239 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
240 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16TriggerMessageRequest
>(
241 'assets/json-schemas/ocpp/1.6/TriggerMessage.json',
247 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
248 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16DataTransferRequest
>(
249 'assets/json-schemas/ocpp/1.6/DataTransfer.json',
255 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
,
256 OCPP16ServiceUtils
.parseJsonSchemaFile
<OCPP16UpdateFirmwareRequest
>(
257 'assets/json-schemas/ocpp/1.6/UpdateFirmware.json',
263 this.validatePayload
= this.validatePayload
.bind(this) as (
264 chargingStation
: ChargingStation
,
265 commandName
: OCPP16IncomingRequestCommand
,
266 commandPayload
: JsonType
270 public async incomingRequestHandler(
271 chargingStation
: ChargingStation
,
273 commandName
: OCPP16IncomingRequestCommand
,
274 commandPayload
: JsonType
276 let response
: JsonType
;
278 chargingStation
.getOcppStrictCompliance() === true &&
279 chargingStation
.inPendingState() === true &&
280 (commandName
=== OCPP16IncomingRequestCommand
.REMOTE_START_TRANSACTION
||
281 commandName
=== OCPP16IncomingRequestCommand
.REMOTE_STOP_TRANSACTION
)
284 ErrorType
.SECURITY_ERROR
,
285 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
289 )} while the charging station is in pending state on the central server`,
295 chargingStation
.isRegistered() === true ||
296 (chargingStation
.getOcppStrictCompliance() === false &&
297 chargingStation
.inUnknownState() === true)
300 this.incomingRequestHandlers
.has(commandName
) === true &&
301 OCPP16ServiceUtils
.isIncomingRequestCommandSupported(chargingStation
, commandName
) === true
304 this.validatePayload(chargingStation
, commandName
, commandPayload
);
305 // Call the method to build the response
306 response
= await this.incomingRequestHandlers
.get(commandName
)(
313 `${chargingStation.logPrefix()} ${moduleName}.incomingRequestHandler: Handle incoming request error:`,
321 ErrorType
.NOT_IMPLEMENTED
,
322 `${commandName} is not implemented to handle request PDU ${JSON.stringify(
333 ErrorType
.SECURITY_ERROR
,
334 `${commandName} cannot be issued to handle request PDU ${JSON.stringify(
338 )} while the charging station is not registered on the central server.`,
343 // Send the built response
344 await chargingStation
.ocppRequestService
.sendResponse(
352 private validatePayload(
353 chargingStation
: ChargingStation
,
354 commandName
: OCPP16IncomingRequestCommand
,
355 commandPayload
: JsonType
357 if (this.jsonSchemas
.has(commandName
) === true) {
358 return this.validateIncomingRequestPayload(
361 this.jsonSchemas
.get(commandName
),
366 `${chargingStation.logPrefix()} ${moduleName}.validatePayload: No JSON schema found for command '${commandName}' PDU validation`
371 // Simulate charging station restart
372 private handleRequestReset(
373 chargingStation
: ChargingStation
,
374 commandPayload
: ResetRequest
376 this.runInAsyncScope(
377 chargingStation
.reset
.bind(chargingStation
) as (
378 this: ChargingStation
,
382 `${commandPayload.type}Reset` as OCPP16StopTransactionReason
383 ).catch(Constants
.EMPTY_FUNCTION
);
385 `${chargingStation.logPrefix()} ${
387 } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
388 chargingStation.stationInfo.resetTime
391 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
394 private async handleRequestUnlockConnector(
395 chargingStation
: ChargingStation
,
396 commandPayload
: UnlockConnectorRequest
397 ): Promise
<UnlockConnectorResponse
> {
398 const connectorId
= commandPayload
.connectorId
;
399 if (chargingStation
.hasConnector(connectorId
) === false) {
401 `${chargingStation.logPrefix()} Trying to unlock a non existing connector id ${connectorId.toString()}`
403 return OCPP16Constants
.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED
;
405 if (connectorId
=== 0) {
407 `${chargingStation.logPrefix()} Trying to unlock connector id ${connectorId.toString()}`
409 return OCPP16Constants
.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED
;
411 if (chargingStation
.getConnectorStatus(connectorId
)?.transactionStarted
=== true) {
412 const stopResponse
= await chargingStation
.stopTransactionOnConnector(
414 OCPP16StopTransactionReason
.UNLOCK_COMMAND
416 if (stopResponse
.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
417 return OCPP16Constants
.OCPP_RESPONSE_UNLOCKED
;
419 return OCPP16Constants
.OCPP_RESPONSE_UNLOCK_FAILED
;
421 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
424 OCPP16ChargePointStatus
.Available
426 return OCPP16Constants
.OCPP_RESPONSE_UNLOCKED
;
429 private handleRequestGetConfiguration(
430 chargingStation
: ChargingStation
,
431 commandPayload
: GetConfigurationRequest
432 ): GetConfigurationResponse
{
433 const configurationKey
: OCPPConfigurationKey
[] = [];
434 const unknownKey
: string[] = [];
435 if (Utils
.isUndefined(commandPayload
.key
) === true) {
436 for (const configuration
of chargingStation
.ocppConfiguration
.configurationKey
) {
437 if (Utils
.isUndefined(configuration
.visible
) === true) {
438 configuration
.visible
= true;
440 if (configuration
.visible
=== false) {
443 configurationKey
.push({
444 key
: configuration
.key
,
445 readonly: configuration
.readonly,
446 value
: configuration
.value
,
449 } else if (Utils
.isNotEmptyArray(commandPayload
.key
) === true) {
450 for (const key
of commandPayload
.key
) {
451 const keyFound
= ChargingStationConfigurationUtils
.getConfigurationKey(
457 if (Utils
.isUndefined(keyFound
.visible
) === true) {
458 keyFound
.visible
= true;
460 if (keyFound
.visible
=== false) {
463 configurationKey
.push({
465 readonly: keyFound
.readonly,
466 value
: keyFound
.value
,
469 unknownKey
.push(key
);
479 private handleRequestChangeConfiguration(
480 chargingStation
: ChargingStation
,
481 commandPayload
: ChangeConfigurationRequest
482 ): ChangeConfigurationResponse
{
483 const keyToChange
= ChargingStationConfigurationUtils
.getConfigurationKey(
489 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED
;
490 } else if (keyToChange
?.readonly === true) {
491 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_REJECTED
;
492 } else if (keyToChange
?.readonly === false) {
493 let valueChanged
= false;
494 if (keyToChange
.value
!== commandPayload
.value
) {
495 ChargingStationConfigurationUtils
.setConfigurationKeyValue(
498 commandPayload
.value
,
503 let triggerHeartbeatRestart
= false;
504 if (keyToChange
.key
=== OCPP16StandardParametersKey
.HeartBeatInterval
&& valueChanged
) {
505 ChargingStationConfigurationUtils
.setConfigurationKeyValue(
507 OCPP16StandardParametersKey
.HeartbeatInterval
,
510 triggerHeartbeatRestart
= true;
512 if (keyToChange
.key
=== OCPP16StandardParametersKey
.HeartbeatInterval
&& valueChanged
) {
513 ChargingStationConfigurationUtils
.setConfigurationKeyValue(
515 OCPP16StandardParametersKey
.HeartBeatInterval
,
518 triggerHeartbeatRestart
= true;
520 if (triggerHeartbeatRestart
) {
521 chargingStation
.restartHeartbeat();
523 if (keyToChange
.key
=== OCPP16StandardParametersKey
.WebSocketPingInterval
&& valueChanged
) {
524 chargingStation
.restartWebSocketPing();
526 if (keyToChange
.reboot
) {
527 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED
;
529 return OCPP16Constants
.OCPP_CONFIGURATION_RESPONSE_ACCEPTED
;
533 private handleRequestSetChargingProfile(
534 chargingStation
: ChargingStation
,
535 commandPayload
: SetChargingProfileRequest
536 ): SetChargingProfileResponse
{
538 OCPP16ServiceUtils
.checkFeatureProfile(
540 OCPP16SupportedFeatureProfiles
.SmartCharging
,
541 OCPP16IncomingRequestCommand
.SET_CHARGING_PROFILE
544 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED
;
546 if (chargingStation
.hasConnector(commandPayload
.connectorId
) === false) {
548 `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector id ${
549 commandPayload.connectorId
552 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED
;
555 commandPayload
.csChargingProfiles
.chargingProfilePurpose
===
556 OCPP16ChargingProfilePurposeType
.CHARGE_POINT_MAX_PROFILE
&&
557 commandPayload
.connectorId
!== 0
559 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED
;
562 commandPayload
.csChargingProfiles
.chargingProfilePurpose
===
563 OCPP16ChargingProfilePurposeType
.TX_PROFILE
&&
564 (commandPayload
.connectorId
=== 0 ||
565 chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.transactionStarted
===
569 `${chargingStation.logPrefix()} Trying to set transaction charging profile(s) on connector ${
570 commandPayload.connectorId
571 } without a started transaction`
573 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED
;
575 OCPP16ServiceUtils
.setChargingProfile(
577 commandPayload
.connectorId
,
578 commandPayload
.csChargingProfiles
581 `${chargingStation.logPrefix()} Charging profile(s) set on connector id ${
582 commandPayload.connectorId
584 commandPayload
.csChargingProfiles
586 return OCPP16Constants
.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED
;
589 private handleRequestGetCompositeSchedule(
590 chargingStation
: ChargingStation
,
591 commandPayload
: OCPP16GetCompositeScheduleRequest
592 ): OCPP16GetCompositeScheduleResponse
{
594 OCPP16ServiceUtils
.checkFeatureProfile(
596 OCPP16SupportedFeatureProfiles
.SmartCharging
,
597 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
600 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
602 if (chargingStation
.hasConnector(commandPayload
.connectorId
) === false) {
604 `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector id ${
605 commandPayload.connectorId
608 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
612 chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.chargingProfiles
615 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
617 const startDate
= new Date();
618 const endDate
= new Date(startDate
.getTime() + commandPayload
.duration
* 1000);
619 let compositeSchedule
: OCPP16ChargingSchedule
;
620 for (const chargingProfile
of chargingStation
.getConnectorStatus(commandPayload
.connectorId
)
622 // FIXME: build the composite schedule including the local power limit, the stack level, the charging rate unit, etc.
624 chargingProfile
.chargingSchedule
?.startSchedule
>= startDate
&&
625 chargingProfile
.chargingSchedule
?.startSchedule
<= endDate
627 compositeSchedule
= chargingProfile
.chargingSchedule
;
632 status: GenericStatus
.Accepted
,
633 scheduleStart
: compositeSchedule
?.startSchedule
,
634 connectorId
: commandPayload
.connectorId
,
635 chargingSchedule
: compositeSchedule
,
639 private handleRequestClearChargingProfile(
640 chargingStation
: ChargingStation
,
641 commandPayload
: ClearChargingProfileRequest
642 ): ClearChargingProfileResponse
{
644 OCPP16ServiceUtils
.checkFeatureProfile(
646 OCPP16SupportedFeatureProfiles
.SmartCharging
,
647 OCPP16IncomingRequestCommand
.CLEAR_CHARGING_PROFILE
650 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
;
652 if (chargingStation
.hasConnector(commandPayload
.connectorId
) === false) {
654 `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${
655 commandPayload.connectorId
658 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
;
661 !Utils
.isNullOrUndefined(commandPayload
.connectorId
) &&
662 Utils
.isNotEmptyArray(
663 chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.chargingProfiles
666 chargingStation
.getConnectorStatus(commandPayload
.connectorId
).chargingProfiles
= [];
668 `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
669 commandPayload.connectorId
672 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED
;
674 if (Utils
.isNullOrUndefined(commandPayload
.connectorId
)) {
675 let clearedCP
= false;
676 const clearChargingProfiles
= (connectorStatus
: ConnectorStatus
) => {
677 if (Utils
.isNotEmptyArray(connectorStatus
?.chargingProfiles
)) {
678 connectorStatus
?.chargingProfiles
?.forEach(
679 (chargingProfile
: OCPP16ChargingProfile
, index
: number) => {
680 let clearCurrentCP
= false;
681 if (chargingProfile
.chargingProfileId
=== commandPayload
.id
) {
682 clearCurrentCP
= true;
685 !commandPayload
.chargingProfilePurpose
&&
686 chargingProfile
.stackLevel
=== commandPayload
.stackLevel
688 clearCurrentCP
= true;
691 !chargingProfile
.stackLevel
&&
692 chargingProfile
.chargingProfilePurpose
=== commandPayload
.chargingProfilePurpose
694 clearCurrentCP
= true;
697 chargingProfile
.stackLevel
=== commandPayload
.stackLevel
&&
698 chargingProfile
.chargingProfilePurpose
=== commandPayload
.chargingProfilePurpose
700 clearCurrentCP
= true;
702 if (clearCurrentCP
) {
703 connectorStatus
?.chargingProfiles
?.splice(index
, 1);
705 `${chargingStation.logPrefix()} Matching charging profile(s) cleared: %j`,
714 if (chargingStation
.hasEvses
) {
715 for (const evseStatus
of chargingStation
.evses
.values()) {
716 for (const connectorStatus
of evseStatus
.connectors
.values()) {
717 clearChargingProfiles(connectorStatus
);
721 for (const connectorId
of chargingStation
.connectors
.keys()) {
722 clearChargingProfiles(chargingStation
.getConnectorStatus(connectorId
));
726 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED
;
729 return OCPP16Constants
.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN
;
732 private async handleRequestChangeAvailability(
733 chargingStation
: ChargingStation
,
734 commandPayload
: ChangeAvailabilityRequest
735 ): Promise
<ChangeAvailabilityResponse
> {
736 const connectorId
: number = commandPayload
.connectorId
;
737 if (chargingStation
.hasConnector(connectorId
) === false) {
739 `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector id ${connectorId.toString()}`
741 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_REJECTED
;
743 const chargePointStatus
: OCPP16ChargePointStatus
=
744 commandPayload
.type === OCPP16AvailabilityType
.Operative
745 ? OCPP16ChargePointStatus
.Available
746 : OCPP16ChargePointStatus
.Unavailable
;
747 if (connectorId
=== 0) {
748 let response
: ChangeAvailabilityResponse
=
749 OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
;
750 const changeAvailability
= async (id
: number, connectorStatus
: ConnectorStatus
) => {
751 if (connectorStatus
?.transactionStarted
=== true) {
752 response
= OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
;
754 connectorStatus
.availability
= commandPayload
.type;
755 if (response
=== OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
) {
756 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
763 if (chargingStation
.hasEvses
) {
764 for (const evseStatus
of chargingStation
.evses
.values()) {
765 for (const [id
, connectorStatus
] of evseStatus
.connectors
) {
766 await changeAvailability(id
, connectorStatus
);
770 for (const id
of chargingStation
.connectors
.keys()) {
771 await changeAvailability(id
, chargingStation
.getConnectorStatus(id
));
777 (chargingStation
.isChargingStationAvailable() === true ||
778 (chargingStation
.isChargingStationAvailable() === false &&
779 commandPayload
.type === OCPP16AvailabilityType
.Inoperative
))
781 if (chargingStation
.getConnectorStatus(connectorId
)?.transactionStarted
=== true) {
782 chargingStation
.getConnectorStatus(connectorId
).availability
= commandPayload
.type;
783 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
;
785 chargingStation
.getConnectorStatus(connectorId
).availability
= commandPayload
.type;
786 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
791 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
;
793 return OCPP16Constants
.OCPP_AVAILABILITY_RESPONSE_REJECTED
;
796 private async handleRequestRemoteStartTransaction(
797 chargingStation
: ChargingStation
,
798 commandPayload
: RemoteStartTransactionRequest
799 ): Promise
<GenericResponse
> {
800 const transactionConnectorId
= commandPayload
.connectorId
;
801 if (chargingStation
.hasConnector(transactionConnectorId
) === false) {
802 return this.notifyRemoteStartTransactionRejected(
804 transactionConnectorId
,
809 chargingStation
.isChargingStationAvailable() === false ||
810 chargingStation
.isConnectorAvailable(transactionConnectorId
) === false
812 return this.notifyRemoteStartTransactionRejected(
814 transactionConnectorId
,
818 const remoteStartTransactionLogMsg
= `${chargingStation.logPrefix()} Transaction remotely STARTED on ${
819 chargingStation.stationInfo.chargingStationId
820 }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`;
821 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
823 transactionConnectorId
,
824 OCPP16ChargePointStatus
.Preparing
826 const connectorStatus
= chargingStation
.getConnectorStatus(transactionConnectorId
);
827 // Check if authorized
828 if (chargingStation
.getAuthorizeRemoteTxRequests() === true) {
829 let authorized
= false;
831 chargingStation
.getLocalAuthListEnabled() === true &&
832 chargingStation
.hasIdTags() === true &&
833 Utils
.isNotEmptyString(
834 chargingStation
.idTagsCache
835 .getIdTags(ChargingStationUtils
.getIdTagsFile(chargingStation
.stationInfo
))
836 ?.find((idTag
) => idTag
=== commandPayload
.idTag
)
839 connectorStatus
.localAuthorizeIdTag
= commandPayload
.idTag
;
840 connectorStatus
.idTagLocalAuthorized
= true;
842 } else if (chargingStation
.getMustAuthorizeAtRemoteStart() === true) {
843 connectorStatus
.authorizeIdTag
= commandPayload
.idTag
;
844 const authorizeResponse
: OCPP16AuthorizeResponse
=
845 await chargingStation
.ocppRequestService
.requestHandler
<
846 OCPP16AuthorizeRequest
,
847 OCPP16AuthorizeResponse
848 >(chargingStation
, OCPP16RequestCommand
.AUTHORIZE
, {
849 idTag
: commandPayload
.idTag
,
851 if (authorizeResponse
?.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
856 `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
859 if (authorized
=== true) {
860 // Authorization successful, start transaction
862 this.setRemoteStartTransactionChargingProfile(
864 transactionConnectorId
,
865 commandPayload
.chargingProfile
868 connectorStatus
.transactionRemoteStarted
= true;
871 await chargingStation
.ocppRequestService
.requestHandler
<
872 OCPP16StartTransactionRequest
,
873 OCPP16StartTransactionResponse
874 >(chargingStation
, OCPP16RequestCommand
.START_TRANSACTION
, {
875 connectorId
: transactionConnectorId
,
876 idTag
: commandPayload
.idTag
,
878 ).idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
880 logger
.debug(remoteStartTransactionLogMsg
);
881 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
883 return this.notifyRemoteStartTransactionRejected(
885 transactionConnectorId
,
889 return this.notifyRemoteStartTransactionRejected(
891 transactionConnectorId
,
895 return this.notifyRemoteStartTransactionRejected(
897 transactionConnectorId
,
901 // No authorization check required, start transaction
903 this.setRemoteStartTransactionChargingProfile(
905 transactionConnectorId
,
906 commandPayload
.chargingProfile
909 connectorStatus
.transactionRemoteStarted
= true;
912 await chargingStation
.ocppRequestService
.requestHandler
<
913 OCPP16StartTransactionRequest
,
914 OCPP16StartTransactionResponse
915 >(chargingStation
, OCPP16RequestCommand
.START_TRANSACTION
, {
916 connectorId
: transactionConnectorId
,
917 idTag
: commandPayload
.idTag
,
919 ).idTagInfo
.status === OCPP16AuthorizationStatus
.ACCEPTED
921 logger
.debug(remoteStartTransactionLogMsg
);
922 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
924 return this.notifyRemoteStartTransactionRejected(
926 transactionConnectorId
,
930 return this.notifyRemoteStartTransactionRejected(
932 transactionConnectorId
,
937 private async notifyRemoteStartTransactionRejected(
938 chargingStation
: ChargingStation
,
941 ): Promise
<GenericResponse
> {
943 chargingStation
.getConnectorStatus(connectorId
)?.status !== OCPP16ChargePointStatus
.Available
945 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
948 OCPP16ChargePointStatus
.Available
952 `${chargingStation.logPrefix()} Remote starting transaction REJECTED on connector id ${connectorId.toString()}, idTag '${idTag}', availability '${
953 chargingStation.getConnectorStatus(connectorId)?.availability
954 }', status '${chargingStation.getConnectorStatus(connectorId)?.status}'`
956 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
959 private setRemoteStartTransactionChargingProfile(
960 chargingStation
: ChargingStation
,
962 cp
: OCPP16ChargingProfile
964 if (cp
&& cp
.chargingProfilePurpose
=== OCPP16ChargingProfilePurposeType
.TX_PROFILE
) {
965 OCPP16ServiceUtils
.setChargingProfile(chargingStation
, connectorId
, cp
);
967 `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}: %j`,
971 } else if (cp
&& cp
.chargingProfilePurpose
!== OCPP16ChargingProfilePurposeType
.TX_PROFILE
) {
973 `${chargingStation.logPrefix()} Not allowed to set ${
974 cp.chargingProfilePurpose
975 } charging profile(s) at remote start transaction`
983 private async handleRequestRemoteStopTransaction(
984 chargingStation
: ChargingStation
,
985 commandPayload
: RemoteStopTransactionRequest
986 ): Promise
<GenericResponse
> {
987 const transactionId
= commandPayload
.transactionId
;
988 const remoteStopTransaction
= async (connectorId
: number): Promise
<GenericResponse
> => {
989 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
992 OCPP16ChargePointStatus
.Finishing
994 const stopResponse
= await chargingStation
.stopTransactionOnConnector(
996 OCPP16StopTransactionReason
.REMOTE
998 if (stopResponse
.idTagInfo
?.status === OCPP16AuthorizationStatus
.ACCEPTED
) {
999 return OCPP16Constants
.OCPP_RESPONSE_ACCEPTED
;
1001 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
1003 if (chargingStation
.hasEvses
) {
1004 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
1006 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1007 if (connectorStatus
.transactionId
=== transactionId
) {
1008 return remoteStopTransaction(connectorId
);
1014 for (const connectorId
of chargingStation
.connectors
.keys()) {
1017 chargingStation
.getConnectorStatus(connectorId
)?.transactionId
=== transactionId
1019 return remoteStopTransaction(connectorId
);
1024 `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction with id: ${transactionId.toString()}`
1026 return OCPP16Constants
.OCPP_RESPONSE_REJECTED
;
1029 private handleRequestUpdateFirmware(
1030 chargingStation
: ChargingStation
,
1031 commandPayload
: OCPP16UpdateFirmwareRequest
1032 ): OCPP16UpdateFirmwareResponse
{
1034 OCPP16ServiceUtils
.checkFeatureProfile(
1036 OCPP16SupportedFeatureProfiles
.FirmwareManagement
,
1037 OCPP16IncomingRequestCommand
.UPDATE_FIRMWARE
1041 `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: feature profile not supported`
1043 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1046 !Utils
.isNullOrUndefined(chargingStation
.stationInfo
.firmwareStatus
) &&
1047 chargingStation
.stationInfo
.firmwareStatus
!== OCPP16FirmwareStatus
.Installed
1050 `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: firmware update is already in progress`
1052 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1054 const retrieveDate
= Utils
.convertToDate(commandPayload
.retrieveDate
);
1055 const now
= Date.now();
1056 if (retrieveDate
?.getTime() <= now
) {
1057 this.runInAsyncScope(
1058 this.updateFirmwareSimulation
.bind(this) as (
1059 this: OCPP16IncomingRequestService
,
1064 ).catch(Constants
.EMPTY_FUNCTION
);
1067 this.updateFirmwareSimulation(chargingStation
).catch(Constants
.EMPTY_FUNCTION
);
1068 }, retrieveDate
?.getTime() - now
);
1070 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1073 private async updateFirmwareSimulation(
1074 chargingStation
: ChargingStation
,
1079 ChargingStationUtils
.checkChargingStation(chargingStation
, chargingStation
.logPrefix()) ===
1084 if (chargingStation
.hasEvses
) {
1085 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
1087 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1088 if (connectorStatus
?.transactionStarted
=== false) {
1089 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1092 OCPP16ChargePointStatus
.Unavailable
1099 for (const connectorId
of chargingStation
.connectors
.keys()) {
1102 chargingStation
.getConnectorStatus(connectorId
)?.transactionStarted
=== false
1104 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1107 OCPP16ChargePointStatus
.Unavailable
1112 await chargingStation
.ocppRequestService
.requestHandler
<
1113 OCPP16FirmwareStatusNotificationRequest
,
1114 OCPP16FirmwareStatusNotificationResponse
1115 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1116 status: OCPP16FirmwareStatus
.Downloading
,
1118 chargingStation
.stationInfo
.firmwareStatus
= OCPP16FirmwareStatus
.Downloading
;
1120 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
===
1121 OCPP16FirmwareStatus
.DownloadFailed
1123 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1124 await chargingStation
.ocppRequestService
.requestHandler
<
1125 OCPP16FirmwareStatusNotificationRequest
,
1126 OCPP16FirmwareStatusNotificationResponse
1127 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1128 status: chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
,
1130 chargingStation
.stationInfo
.firmwareStatus
=
1131 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
;
1134 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1135 await chargingStation
.ocppRequestService
.requestHandler
<
1136 OCPP16FirmwareStatusNotificationRequest
,
1137 OCPP16FirmwareStatusNotificationResponse
1138 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1139 status: OCPP16FirmwareStatus
.Downloaded
,
1141 chargingStation
.stationInfo
.firmwareStatus
= OCPP16FirmwareStatus
.Downloaded
;
1142 let wasTransactionsStarted
= false;
1143 let transactionsStarted
: boolean;
1145 const runningTransactions
= chargingStation
.getNumberOfRunningTransactions();
1146 if (runningTransactions
> 0) {
1147 const waitTime
= 15 * 1000;
1149 `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${runningTransactions} transaction(s) in progress, waiting ${
1151 } seconds before continuing firmware update simulation`
1153 await Utils
.sleep(waitTime
);
1154 transactionsStarted
= true;
1155 wasTransactionsStarted
= true;
1157 if (chargingStation
.hasEvses
) {
1158 for (const [evseId
, evseStatus
] of chargingStation
.evses
) {
1160 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1161 if (connectorStatus
?.status !== OCPP16ChargePointStatus
.Unavailable
) {
1162 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1165 OCPP16ChargePointStatus
.Unavailable
1172 for (const connectorId
of chargingStation
.connectors
.keys()) {
1175 chargingStation
.getConnectorStatus(connectorId
)?.status !==
1176 OCPP16ChargePointStatus
.Unavailable
1178 await OCPP16ServiceUtils
.sendAndSetConnectorStatus(
1181 OCPP16ChargePointStatus
.Unavailable
1186 transactionsStarted
= false;
1188 } while (transactionsStarted
);
1189 !wasTransactionsStarted
&&
1190 (await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000));
1192 ChargingStationUtils
.checkChargingStation(chargingStation
, chargingStation
.logPrefix()) ===
1197 await chargingStation
.ocppRequestService
.requestHandler
<
1198 OCPP16FirmwareStatusNotificationRequest
,
1199 OCPP16FirmwareStatusNotificationResponse
1200 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1201 status: OCPP16FirmwareStatus
.Installing
,
1203 chargingStation
.stationInfo
.firmwareStatus
= OCPP16FirmwareStatus
.Installing
;
1205 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
===
1206 OCPP16FirmwareStatus
.InstallationFailed
1208 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1209 await chargingStation
.ocppRequestService
.requestHandler
<
1210 OCPP16FirmwareStatusNotificationRequest
,
1211 OCPP16FirmwareStatusNotificationResponse
1212 >(chargingStation
, OCPP16RequestCommand
.FIRMWARE_STATUS_NOTIFICATION
, {
1213 status: chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
,
1215 chargingStation
.stationInfo
.firmwareStatus
=
1216 chargingStation
.stationInfo
?.firmwareUpgrade
?.failureStatus
;
1219 if (chargingStation
.stationInfo
?.firmwareUpgrade
?.reset
=== true) {
1220 await Utils
.sleep(Utils
.getRandomInteger(maxDelay
, minDelay
) * 1000);
1221 await chargingStation
.reset(OCPP16StopTransactionReason
.REBOOT
);
1225 private async handleRequestGetDiagnostics(
1226 chargingStation
: ChargingStation
,
1227 commandPayload
: GetDiagnosticsRequest
1228 ): Promise
<GetDiagnosticsResponse
> {
1230 OCPP16ServiceUtils
.checkFeatureProfile(
1232 OCPP16SupportedFeatureProfiles
.FirmwareManagement
,
1233 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
1237 `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Cannot get diagnostics: feature profile not supported`
1239 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1241 const uri
= new URL(commandPayload
.location
);
1242 if (uri
.protocol
.startsWith('ftp:')) {
1243 let ftpClient
: Client
;
1246 .readdirSync(path
.resolve(path
.dirname(fileURLToPath(import.meta
.url
)), '../'))
1247 .filter((file
) => file
.endsWith('.log'))
1248 .map((file
) => path
.join('./', file
));
1249 const diagnosticsArchive
= `${chargingStation.stationInfo.chargingStationId}_logs.tar.gz`;
1250 tar
.create({ gzip
: true }, logFiles
).pipe(fs
.createWriteStream(diagnosticsArchive
));
1251 ftpClient
= new Client();
1252 const accessResponse
= await ftpClient
.access({
1254 ...(Utils
.isNotEmptyString(uri
.port
) && { port
: Utils
.convertToInt(uri
.port
) }),
1255 ...(Utils
.isNotEmptyString(uri
.username
) && { user
: uri
.username
}),
1256 ...(Utils
.isNotEmptyString(uri
.password
) && { password
: uri
.password
}),
1258 let uploadResponse
: FTPResponse
;
1259 if (accessResponse
.code
=== 220) {
1260 ftpClient
.trackProgress((info
) => {
1262 `${chargingStation.logPrefix()} ${
1264 } bytes transferred from diagnostics archive ${info.name}`
1266 chargingStation
.ocppRequestService
1268 OCPP16DiagnosticsStatusNotificationRequest
,
1269 OCPP16DiagnosticsStatusNotificationResponse
1270 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1271 status: OCPP16DiagnosticsStatus
.Uploading
,
1275 `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Error while sending '${
1276 OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION
1282 uploadResponse
= await ftpClient
.uploadFrom(
1284 path
.resolve(path
.dirname(fileURLToPath(import.meta
.url
)), '../'),
1287 `${uri.pathname}${diagnosticsArchive}`
1289 if (uploadResponse
.code
=== 226) {
1290 await chargingStation
.ocppRequestService
.requestHandler
<
1291 OCPP16DiagnosticsStatusNotificationRequest
,
1292 OCPP16DiagnosticsStatusNotificationResponse
1293 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1294 status: OCPP16DiagnosticsStatus
.Uploaded
,
1299 return { fileName
: diagnosticsArchive
};
1301 throw new OCPPError(
1302 ErrorType
.GENERIC_ERROR
,
1303 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1304 uploadResponse?.code && `|${uploadResponse?.code.toString()}
`
1306 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
1309 throw new OCPPError(
1310 ErrorType
.GENERIC_ERROR
,
1311 `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
1312 uploadResponse?.code && `|${uploadResponse?.code.toString()}
`
1314 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
1317 await chargingStation
.ocppRequestService
.requestHandler
<
1318 OCPP16DiagnosticsStatusNotificationRequest
,
1319 OCPP16DiagnosticsStatusNotificationResponse
1320 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1321 status: OCPP16DiagnosticsStatus
.UploadFailed
,
1326 return this.handleIncomingRequestError(
1328 OCPP16IncomingRequestCommand
.GET_DIAGNOSTICS
,
1330 { errorResponse
: OCPP16Constants
.OCPP_RESPONSE_EMPTY
}
1335 `${chargingStation.logPrefix()} Unsupported protocol ${
1337 } to transfer the diagnostic logs archive`
1339 await chargingStation
.ocppRequestService
.requestHandler
<
1340 OCPP16DiagnosticsStatusNotificationRequest
,
1341 OCPP16DiagnosticsStatusNotificationResponse
1342 >(chargingStation
, OCPP16RequestCommand
.DIAGNOSTICS_STATUS_NOTIFICATION
, {
1343 status: OCPP16DiagnosticsStatus
.UploadFailed
,
1345 return OCPP16Constants
.OCPP_RESPONSE_EMPTY
;
1349 private handleRequestTriggerMessage(
1350 chargingStation
: ChargingStation
,
1351 commandPayload
: OCPP16TriggerMessageRequest
1352 ): OCPP16TriggerMessageResponse
{
1354 !OCPP16ServiceUtils
.checkFeatureProfile(
1356 OCPP16SupportedFeatureProfiles
.RemoteTrigger
,
1357 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
1359 !OCPP16ServiceUtils
.isMessageTriggerSupported(
1361 commandPayload
.requestedMessage
1364 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED
;
1367 !OCPP16ServiceUtils
.isConnectorIdValid(
1369 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
1370 commandPayload
.connectorId
1373 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED
;
1376 switch (commandPayload
.requestedMessage
) {
1377 case OCPP16MessageTrigger
.BootNotification
:
1379 chargingStation
.ocppRequestService
1380 .requestHandler
<OCPP16BootNotificationRequest
, OCPP16BootNotificationResponse
>(
1382 OCPP16RequestCommand
.BOOT_NOTIFICATION
,
1383 chargingStation
.bootNotificationRequest
,
1384 { skipBufferingOnError
: true, triggerMessage
: true }
1386 .then((response
) => {
1387 chargingStation
.bootNotificationResponse
= response
;
1389 .catch(Constants
.EMPTY_FUNCTION
);
1390 }, OCPP16Constants
.OCPP_TRIGGER_MESSAGE_DELAY
);
1391 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
;
1392 case OCPP16MessageTrigger
.Heartbeat
:
1394 chargingStation
.ocppRequestService
1395 .requestHandler
<OCPP16HeartbeatRequest
, OCPP16HeartbeatResponse
>(
1397 OCPP16RequestCommand
.HEARTBEAT
,
1400 triggerMessage
: true,
1403 .catch(Constants
.EMPTY_FUNCTION
);
1404 }, OCPP16Constants
.OCPP_TRIGGER_MESSAGE_DELAY
);
1405 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
;
1406 case OCPP16MessageTrigger
.StatusNotification
:
1408 if (!Utils
.isNullOrUndefined(commandPayload
?.connectorId
)) {
1409 chargingStation
.ocppRequestService
1410 .requestHandler
<OCPP16StatusNotificationRequest
, OCPP16StatusNotificationResponse
>(
1412 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
1414 connectorId
: commandPayload
.connectorId
,
1415 errorCode
: OCPP16ChargePointErrorCode
.NO_ERROR
,
1416 status: chargingStation
.getConnectorStatus(commandPayload
.connectorId
)?.status,
1419 triggerMessage
: true,
1422 .catch(Constants
.EMPTY_FUNCTION
);
1424 // eslint-disable-next-line no-lonely-if
1425 if (chargingStation
.hasEvses
) {
1426 for (const evseStatus
of chargingStation
.evses
.values()) {
1427 for (const [connectorId
, connectorStatus
] of evseStatus
.connectors
) {
1428 chargingStation
.ocppRequestService
1430 OCPP16StatusNotificationRequest
,
1431 OCPP16StatusNotificationResponse
1434 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
1437 errorCode
: OCPP16ChargePointErrorCode
.NO_ERROR
,
1438 status: connectorStatus
.status,
1441 triggerMessage
: true,
1444 .catch(Constants
.EMPTY_FUNCTION
);
1448 for (const connectorId
of chargingStation
.connectors
.keys()) {
1449 chargingStation
.ocppRequestService
1451 OCPP16StatusNotificationRequest
,
1452 OCPP16StatusNotificationResponse
1455 OCPP16RequestCommand
.STATUS_NOTIFICATION
,
1458 errorCode
: OCPP16ChargePointErrorCode
.NO_ERROR
,
1459 status: chargingStation
.getConnectorStatus(connectorId
)?.status,
1462 triggerMessage
: true,
1465 .catch(Constants
.EMPTY_FUNCTION
);
1469 }, OCPP16Constants
.OCPP_TRIGGER_MESSAGE_DELAY
);
1470 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED
;
1472 return OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED
;
1475 return this.handleIncomingRequestError(
1477 OCPP16IncomingRequestCommand
.TRIGGER_MESSAGE
,
1479 { errorResponse
: OCPP16Constants
.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED
}
1484 private handleRequestDataTransfer(
1485 chargingStation
: ChargingStation
,
1486 commandPayload
: OCPP16DataTransferRequest
1487 ): OCPP16DataTransferResponse
{
1489 if (Object.values(OCPP16DataTransferVendorId
).includes(commandPayload
.vendorId
)) {
1490 return OCPP16Constants
.OCPP_DATA_TRANSFER_RESPONSE_ACCEPTED
;
1492 return OCPP16Constants
.OCPP_DATA_TRANSFER_RESPONSE_UNKNOWN_VENDOR_ID
;
1494 return this.handleIncomingRequestError(
1496 OCPP16IncomingRequestCommand
.DATA_TRANSFER
,
1498 { errorResponse
: OCPP16Constants
.OCPP_DATA_TRANSFER_RESPONSE_REJECTED
}