X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2F1.6%2FOCPP16IncomingRequestService.ts;h=a33d0c26a60bb362f449c29d65b2bac57dd23e41;hb=4c3c0d59f56be4d58e906e938c00390b41e0ca7f;hp=49ed8c92ae99ffd93fb4495d4fb916c8c73da925;hpb=4ecff7ce6e87af51f1ff04e95641aee2270fbdb0;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 49ed8c92..a33d0c26 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -8,6 +8,8 @@ import type { JSONSchemaType } from 'ajv'; import { Client, type FTPResponse } from 'basic-ftp'; import tar from 'tar'; +import { OCPP16Constants } from './OCPP16Constants'; +import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import { type ChargingStation, ChargingStationConfigurationUtils, @@ -21,6 +23,7 @@ import { type ChangeConfigurationResponse, type ClearChargingProfileRequest, type ClearChargingProfileResponse, + type ConnectorStatus, ErrorType, type GenericResponse, GenericStatus, @@ -82,7 +85,7 @@ import { type UnlockConnectorResponse, } from '../../../types'; import { Constants, Utils, logger } from '../../../utils'; -import { OCPP16ServiceUtils, OCPPConstants, OCPPIncomingRequestService } from '../internal'; +import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService'; const moduleName = 'OCPP16IncomingRequestService'; @@ -274,7 +277,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { let response: JsonType; if ( chargingStation.getOcppStrictCompliance() === true && - chargingStation.isInPendingState() === true && + chargingStation.inPendingState() === true && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION) ) { @@ -292,7 +295,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { if ( chargingStation.isRegistered() === true || (chargingStation.getOcppStrictCompliance() === false && - chargingStation.isInUnknownState() === true) + chargingStation.inUnknownState() === true) ) { if ( this.incomingRequestHandlers.has(commandName) === true && @@ -386,7 +389,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.stationInfo.resetTime )}` ); - return OCPPConstants.OCPP_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED; } private async handleRequestUnlockConnector( @@ -394,17 +397,17 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload: UnlockConnectorRequest ): Promise { const connectorId = commandPayload.connectorId; - if (chargingStation.connectors.has(connectorId) === false) { + if (chargingStation.hasConnector(connectorId) === false) { logger.error( - `${chargingStation.logPrefix()} Trying to unlock a non existing connector Id ${connectorId.toString()}` + `${chargingStation.logPrefix()} Trying to unlock a non existing connector id ${connectorId.toString()}` ); - return OCPPConstants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED; + return OCPP16Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED; } if (connectorId === 0) { logger.error( - `${chargingStation.logPrefix()} Trying to unlock connector Id ${connectorId.toString()}` + `${chargingStation.logPrefix()} Trying to unlock connector id ${connectorId.toString()}` ); - return OCPPConstants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED; + return OCPP16Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED; } if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) { const stopResponse = await chargingStation.stopTransactionOnConnector( @@ -412,16 +415,16 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { OCPP16StopTransactionReason.UNLOCK_COMMAND ); if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { - return OCPPConstants.OCPP_RESPONSE_UNLOCKED; + return OCPP16Constants.OCPP_RESPONSE_UNLOCKED; } - return OCPPConstants.OCPP_RESPONSE_UNLOCK_FAILED; + return OCPP16Constants.OCPP_RESPONSE_UNLOCK_FAILED; } await OCPP16ServiceUtils.sendAndSetConnectorStatus( chargingStation, connectorId, OCPP16ChargePointStatus.Available ); - return OCPPConstants.OCPP_RESPONSE_UNLOCKED; + return OCPP16Constants.OCPP_RESPONSE_UNLOCKED; } private handleRequestGetConfiguration( @@ -484,10 +487,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { true ); if (!keyToChange) { - return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED; - } else if (keyToChange && keyToChange.readonly) { - return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_REJECTED; - } else if (keyToChange && !keyToChange.readonly) { + return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED; + } else if (keyToChange?.readonly === true) { + return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED; + } else if (keyToChange?.readonly === false) { let valueChanged = false; if (keyToChange.value !== commandPayload.value) { ChargingStationConfigurationUtils.setConfigurationKeyValue( @@ -522,9 +525,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.restartWebSocketPing(); } if (keyToChange.reboot) { - return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED; + return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED; } - return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_ACCEPTED; } } @@ -539,22 +542,22 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE ) === false ) { - return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED; + return OCPP16Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED; } - if (chargingStation.connectors.has(commandPayload.connectorId) === false) { + if (chargingStation.hasConnector(commandPayload.connectorId) === false) { logger.error( - `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${ + `${chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector id ${ commandPayload.connectorId }` ); - return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; } if ( commandPayload.csChargingProfiles.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE && commandPayload.connectorId !== 0 ) { - return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; } if ( commandPayload.csChargingProfiles.chargingProfilePurpose === @@ -568,7 +571,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload.connectorId } without a started transaction` ); - return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; } OCPP16ServiceUtils.setChargingProfile( chargingStation, @@ -581,7 +584,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { }: %j`, commandPayload.csChargingProfiles ); - return OCPPConstants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED; } private handleRequestGetCompositeSchedule( @@ -595,22 +598,22 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE ) === false ) { - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } - if (chargingStation.connectors.has(commandPayload.connectorId) === false) { + if (chargingStation.hasConnector(commandPayload.connectorId) === false) { logger.error( - `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector Id ${ + `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector id ${ commandPayload.connectorId }` ); - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } if ( Utils.isEmptyArray( chargingStation.getConnectorStatus(commandPayload.connectorId)?.chargingProfiles ) ) { - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } const startDate = new Date(); const endDate = new Date(startDate.getTime() + commandPayload.duration * 1000); @@ -645,38 +648,36 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE ) === false ) { - return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; } - if (chargingStation.connectors.has(commandPayload.connectorId) === false) { + if (chargingStation.hasConnector(commandPayload.connectorId) === false) { logger.error( - `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${ + `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${ commandPayload.connectorId }` ); - return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; } - const connectorStatus = chargingStation.getConnectorStatus(commandPayload.connectorId); if ( !Utils.isNullOrUndefined(commandPayload.connectorId) && - Utils.isNotEmptyArray(connectorStatus?.chargingProfiles) + Utils.isNotEmptyArray( + chargingStation.getConnectorStatus(commandPayload.connectorId)?.chargingProfiles + ) ) { - connectorStatus.chargingProfiles = []; + chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles = []; logger.debug( `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${ commandPayload.connectorId }` ); - return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED; } if (Utils.isNullOrUndefined(commandPayload.connectorId)) { let clearedCP = false; - for (const connectorId of chargingStation.connectors.keys()) { - if ( - Utils.isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles) - ) { - chargingStation - .getConnectorStatus(connectorId) - ?.chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => { + const clearChargingProfiles = (connectorStatus: ConnectorStatus) => { + if (Utils.isNotEmptyArray(connectorStatus?.chargingProfiles)) { + connectorStatus?.chargingProfiles?.forEach( + (chargingProfile: OCPP16ChargingProfile, index: number) => { let clearCurrentCP = false; if (chargingProfile.chargingProfileId === commandPayload.id) { clearCurrentCP = true; @@ -707,14 +708,26 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ); clearedCP = true; } - }); + } + ); + } + }; + if (chargingStation.hasEvses) { + for (const evseStatus of chargingStation.evses.values()) { + for (const connectorStatus of evseStatus.connectors.values()) { + clearChargingProfiles(connectorStatus); + } + } + } else { + for (const connectorId of chargingStation.connectors.keys()) { + clearChargingProfiles(chargingStation.getConnectorStatus(connectorId)); } } if (clearedCP) { - return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED; } } - return OCPPConstants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; } private async handleRequestChangeAvailability( @@ -722,41 +735,53 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload: ChangeAvailabilityRequest ): Promise { const connectorId: number = commandPayload.connectorId; - if (chargingStation.connectors.has(connectorId) === false) { + if (chargingStation.hasConnector(connectorId) === false) { logger.error( - `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}` + `${chargingStation.logPrefix()} Trying to change the availability of a non existing connector id ${connectorId.toString()}` ); - return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED; } const chargePointStatus: OCPP16ChargePointStatus = - commandPayload.type === OCPP16AvailabilityType.OPERATIVE + commandPayload.type === OCPP16AvailabilityType.Operative ? OCPP16ChargePointStatus.Available : OCPP16ChargePointStatus.Unavailable; if (connectorId === 0) { - let response: ChangeAvailabilityResponse = OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; - for (const id of chargingStation.connectors.keys()) { - if (chargingStation.getConnectorStatus(id)?.transactionStarted === true) { - response = OCPPConstants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; + let response: ChangeAvailabilityResponse = + OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; + const changeAvailability = async (id: number, connectorStatus: ConnectorStatus) => { + if (connectorStatus?.transactionStarted === true) { + response = OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } - chargingStation.getConnectorStatus(id).availability = commandPayload.type; - if (response === OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) { + connectorStatus.availability = commandPayload.type; + if (response === OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) { await OCPP16ServiceUtils.sendAndSetConnectorStatus( chargingStation, id, chargePointStatus ); } + }; + if (chargingStation.hasEvses) { + for (const evseStatus of chargingStation.evses.values()) { + for (const [id, connectorStatus] of evseStatus.connectors) { + await changeAvailability(id, connectorStatus); + } + } + } else { + for (const id of chargingStation.connectors.keys()) { + await changeAvailability(id, chargingStation.getConnectorStatus(id)); + } } return response; } else if ( connectorId > 0 && (chargingStation.isChargingStationAvailable() === true || (chargingStation.isChargingStationAvailable() === false && - commandPayload.type === OCPP16AvailabilityType.INOPERATIVE)) + commandPayload.type === OCPP16AvailabilityType.Inoperative)) ) { if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true) { chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type; - return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; + return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type; await OCPP16ServiceUtils.sendAndSetConnectorStatus( @@ -764,9 +789,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { connectorId, chargePointStatus ); - return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; } - return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED; } private async handleRequestRemoteStartTransaction( @@ -774,95 +799,66 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload: RemoteStartTransactionRequest ): Promise { const transactionConnectorId = commandPayload.connectorId; - if (chargingStation.connectors.has(transactionConnectorId) === true) { - const remoteStartTransactionLogMsg = `${chargingStation.logPrefix()} Transaction remotely STARTED on ${ - chargingStation.stationInfo.chargingStationId - }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`; - await OCPP16ServiceUtils.sendAndSetConnectorStatus( + if (chargingStation.hasConnector(transactionConnectorId) === false) { + return this.notifyRemoteStartTransactionRejected( + chargingStation, + transactionConnectorId, + commandPayload.idTag + ); + } + if ( + chargingStation.isChargingStationAvailable() === false || + chargingStation.isConnectorAvailable(transactionConnectorId) === false + ) { + return this.notifyRemoteStartTransactionRejected( chargingStation, transactionConnectorId, - OCPP16ChargePointStatus.Preparing + commandPayload.idTag ); - const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId); + } + const remoteStartTransactionLogMsg = `${chargingStation.logPrefix()} Transaction remotely STARTED on ${ + chargingStation.stationInfo.chargingStationId + }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`; + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + transactionConnectorId, + OCPP16ChargePointStatus.Preparing + ); + const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId); + // Check if authorized + if (chargingStation.getAuthorizeRemoteTxRequests() === true) { + let authorized = false; if ( - chargingStation.isChargingStationAvailable() === true && - chargingStation.isConnectorAvailable(transactionConnectorId) === true + chargingStation.getLocalAuthListEnabled() === true && + chargingStation.hasIdTags() === true && + Utils.isNotEmptyString( + chargingStation.idTagsCache + .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo)) + ?.find((idTag) => idTag === commandPayload.idTag) + ) ) { - // Check if authorized - if (chargingStation.getAuthorizeRemoteTxRequests() === true) { - let authorized = false; - if ( - chargingStation.getLocalAuthListEnabled() === true && - chargingStation.hasIdTags() === true && - Utils.isNotEmptyString( - chargingStation.idTagsCache - .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo)) - ?.find((idTag) => idTag === commandPayload.idTag) - ) - ) { - connectorStatus.localAuthorizeIdTag = commandPayload.idTag; - connectorStatus.idTagLocalAuthorized = true; - authorized = true; - } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) { - connectorStatus.authorizeIdTag = commandPayload.idTag; - const authorizeResponse: OCPP16AuthorizeResponse = - await chargingStation.ocppRequestService.requestHandler< - OCPP16AuthorizeRequest, - OCPP16AuthorizeResponse - >(chargingStation, OCPP16RequestCommand.AUTHORIZE, { - idTag: commandPayload.idTag, - }); - if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { - authorized = true; - } - } else { - logger.warn( - `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled` - ); - } - if (authorized === true) { - // Authorization successful, start transaction - if ( - this.setRemoteStartTransactionChargingProfile( - chargingStation, - transactionConnectorId, - commandPayload.chargingProfile - ) === true - ) { - connectorStatus.transactionRemoteStarted = true; - if ( - ( - await chargingStation.ocppRequestService.requestHandler< - OCPP16StartTransactionRequest, - OCPP16StartTransactionResponse - >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, { - connectorId: transactionConnectorId, - idTag: commandPayload.idTag, - }) - ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED - ) { - logger.debug(remoteStartTransactionLogMsg); - return OCPPConstants.OCPP_RESPONSE_ACCEPTED; - } - return this.notifyRemoteStartTransactionRejected( - chargingStation, - transactionConnectorId, - commandPayload.idTag - ); - } - return this.notifyRemoteStartTransactionRejected( - chargingStation, - transactionConnectorId, - commandPayload.idTag - ); - } - return this.notifyRemoteStartTransactionRejected( - chargingStation, - transactionConnectorId, - commandPayload.idTag - ); + connectorStatus.localAuthorizeIdTag = commandPayload.idTag; + connectorStatus.idTagLocalAuthorized = true; + authorized = true; + } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) { + connectorStatus.authorizeIdTag = commandPayload.idTag; + const authorizeResponse: OCPP16AuthorizeResponse = + await chargingStation.ocppRequestService.requestHandler< + OCPP16AuthorizeRequest, + OCPP16AuthorizeResponse + >(chargingStation, OCPP16RequestCommand.AUTHORIZE, { + idTag: commandPayload.idTag, + }); + if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { + authorized = true; } - // No authorization check required, start transaction + } else { + logger.warn( + `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled` + ); + } + if (authorized === true) { + // Authorization successful, start transaction if ( this.setRemoteStartTransactionChargingProfile( chargingStation, @@ -883,7 +879,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED ) { logger.debug(remoteStartTransactionLogMsg); - return OCPPConstants.OCPP_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED; } return this.notifyRemoteStartTransactionRejected( chargingStation, @@ -903,6 +899,35 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload.idTag ); } + // No authorization check required, start transaction + if ( + this.setRemoteStartTransactionChargingProfile( + chargingStation, + transactionConnectorId, + commandPayload.chargingProfile + ) === true + ) { + connectorStatus.transactionRemoteStarted = true; + if ( + ( + await chargingStation.ocppRequestService.requestHandler< + OCPP16StartTransactionRequest, + OCPP16StartTransactionResponse + >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, { + connectorId: transactionConnectorId, + idTag: commandPayload.idTag, + }) + ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED + ) { + logger.debug(remoteStartTransactionLogMsg); + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED; + } + return this.notifyRemoteStartTransactionRejected( + chargingStation, + transactionConnectorId, + commandPayload.idTag + ); + } return this.notifyRemoteStartTransactionRejected( chargingStation, transactionConnectorId, @@ -925,11 +950,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ); } logger.warn( - `${chargingStation.logPrefix()} Remote starting transaction REJECTED on connector Id ${connectorId.toString()}, idTag '${idTag}', availability '${ + `${chargingStation.logPrefix()} Remote starting transaction REJECTED on connector id ${connectorId.toString()}, idTag '${idTag}', availability '${ chargingStation.getConnectorStatus(connectorId)?.availability }', status '${chargingStation.getConnectorStatus(connectorId)?.status}'` ); - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } private setRemoteStartTransactionChargingProfile( @@ -961,30 +986,45 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload: RemoteStopTransactionRequest ): Promise { const transactionId = commandPayload.transactionId; - for (const connectorId of chargingStation.connectors.keys()) { - if ( - connectorId > 0 && - chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId - ) { - await OCPP16ServiceUtils.sendAndSetConnectorStatus( - chargingStation, - connectorId, - OCPP16ChargePointStatus.Finishing - ); - const stopResponse = await chargingStation.stopTransactionOnConnector( - connectorId, - OCPP16StopTransactionReason.REMOTE - ); - if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { - return OCPPConstants.OCPP_RESPONSE_ACCEPTED; + const remoteStopTransaction = async (connectorId: number): Promise => { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + connectorId, + OCPP16ChargePointStatus.Finishing + ); + const stopResponse = await chargingStation.stopTransactionOnConnector( + connectorId, + OCPP16StopTransactionReason.REMOTE + ); + if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED; + } + return OCPP16Constants.OCPP_RESPONSE_REJECTED; + }; + if (chargingStation.hasEvses) { + for (const [evseId, evseStatus] of chargingStation.evses) { + if (evseId > 0) { + for (const [connectorId, connectorStatus] of evseStatus.connectors) { + if (connectorStatus.transactionId === transactionId) { + return remoteStopTransaction(connectorId); + } + } + } + } + } else { + for (const connectorId of chargingStation.connectors.keys()) { + if ( + connectorId > 0 && + chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId + ) { + return remoteStopTransaction(connectorId); } - return OCPPConstants.OCPP_RESPONSE_REJECTED; } } logger.warn( - `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction ${transactionId.toString()}` + `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction with id: ${transactionId.toString()}` ); - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } private handleRequestUpdateFirmware( @@ -1001,7 +1041,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: feature profile not supported` ); - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } if ( !Utils.isNullOrUndefined(chargingStation.stationInfo.firmwareStatus) && @@ -1010,7 +1050,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: firmware update is already in progress` ); - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } const retrieveDate = Utils.convertToDate(commandPayload.retrieveDate); const now = Date.now(); @@ -1028,7 +1068,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { this.updateFirmwareSimulation(chargingStation).catch(Constants.EMPTY_FUNCTION); }, retrieveDate?.getTime() - now); } - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } private async updateFirmwareSimulation( @@ -1042,16 +1082,32 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ) { return; } - for (const connectorId of chargingStation.connectors.keys()) { - if ( - connectorId > 0 && - chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false - ) { - await OCPP16ServiceUtils.sendAndSetConnectorStatus( - chargingStation, - connectorId, - OCPP16ChargePointStatus.Unavailable - ); + if (chargingStation.hasEvses) { + for (const [evseId, evseStatus] of chargingStation.evses) { + if (evseId > 0) { + for (const [connectorId, connectorStatus] of evseStatus.connectors) { + if (connectorStatus?.transactionStarted === false) { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + connectorId, + OCPP16ChargePointStatus.Unavailable + ); + } + } + } + } + } else { + for (const connectorId of chargingStation.connectors.keys()) { + if ( + connectorId > 0 && + chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false + ) { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + connectorId, + OCPP16ChargePointStatus.Unavailable + ); + } } } await chargingStation.ocppRequestService.requestHandler< @@ -1087,19 +1143,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { let wasTransactionsStarted = false; let transactionsStarted: boolean; do { - let trxCount = 0; - for (const connectorId of chargingStation.connectors.keys()) { - if ( - connectorId > 0 && - chargingStation.getConnectorStatus(connectorId)?.transactionStarted === true - ) { - trxCount++; - } - } - if (trxCount > 0) { + const runningTransactions = chargingStation.getNumberOfRunningTransactions(); + if (runningTransactions > 0) { const waitTime = 15 * 1000; logger.debug( - `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${trxCount} transaction(s) in progress, waiting ${ + `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${runningTransactions} transaction(s) in progress, waiting ${ waitTime / 1000 } seconds before continuing firmware update simulation` ); @@ -1107,17 +1155,33 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { transactionsStarted = true; wasTransactionsStarted = true; } else { - for (const connectorId of chargingStation.connectors.keys()) { - if ( - connectorId > 0 && - chargingStation.getConnectorStatus(connectorId)?.status !== - OCPP16ChargePointStatus.Unavailable - ) { - await OCPP16ServiceUtils.sendAndSetConnectorStatus( - chargingStation, - connectorId, - OCPP16ChargePointStatus.Unavailable - ); + if (chargingStation.hasEvses) { + for (const [evseId, evseStatus] of chargingStation.evses) { + if (evseId > 0) { + for (const [connectorId, connectorStatus] of evseStatus.connectors) { + if (connectorStatus?.status !== OCPP16ChargePointStatus.Unavailable) { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + connectorId, + OCPP16ChargePointStatus.Unavailable + ); + } + } + } + } + } else { + for (const connectorId of chargingStation.connectors.keys()) { + if ( + connectorId > 0 && + chargingStation.getConnectorStatus(connectorId)?.status !== + OCPP16ChargePointStatus.Unavailable + ) { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + connectorId, + OCPP16ChargePointStatus.Unavailable + ); + } } } transactionsStarted = false; @@ -1173,7 +1237,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Cannot get diagnostics: feature profile not supported` ); - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } const uri = new URL(commandPayload.location); if (uri.protocol.startsWith('ftp:')) { @@ -1264,7 +1328,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, error as Error, - { errorResponse: OCPPConstants.OCPP_RESPONSE_EMPTY } + { errorResponse: OCPP16Constants.OCPP_RESPONSE_EMPTY } ); } } else { @@ -1279,7 +1343,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.UploadFailed, }); - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } } @@ -1298,7 +1362,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload.requestedMessage ) ) { - return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED; + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED; } if ( !OCPP16ServiceUtils.isConnectorIdValid( @@ -1307,7 +1371,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload.connectorId ) ) { - return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED; } try { switch (commandPayload.requestedMessage) { @@ -1324,8 +1388,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.bootNotificationResponse = response; }) .catch(Constants.EMPTY_FUNCTION); - }, Constants.OCPP_TRIGGER_MESSAGE_DELAY); - return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; + }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY); + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; case OCPP16MessageTrigger.Heartbeat: setTimeout(() => { chargingStation.ocppRequestService @@ -1338,8 +1402,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { } ) .catch(Constants.EMPTY_FUNCTION); - }, Constants.OCPP_TRIGGER_MESSAGE_DELAY); - return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; + }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY); + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; case OCPP16MessageTrigger.StatusNotification: setTimeout(() => { if (!Utils.isNullOrUndefined(commandPayload?.connectorId)) { @@ -1358,37 +1422,62 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ) .catch(Constants.EMPTY_FUNCTION); } else { - for (const connectorId of chargingStation.connectors.keys()) { - chargingStation.ocppRequestService - .requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >( - chargingStation, - OCPP16RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - status: chargingStation.getConnectorStatus(connectorId)?.status, - }, - { - triggerMessage: true, - } - ) - .catch(Constants.EMPTY_FUNCTION); + // eslint-disable-next-line no-lonely-if + if (chargingStation.hasEvses) { + for (const evseStatus of chargingStation.evses.values()) { + for (const [connectorId, connectorStatus] of evseStatus.connectors) { + chargingStation.ocppRequestService + .requestHandler< + OCPP16StatusNotificationRequest, + OCPP16StatusNotificationResponse + >( + chargingStation, + OCPP16RequestCommand.STATUS_NOTIFICATION, + { + connectorId, + errorCode: OCPP16ChargePointErrorCode.NO_ERROR, + status: connectorStatus.status, + }, + { + triggerMessage: true, + } + ) + .catch(Constants.EMPTY_FUNCTION); + } + } + } else { + for (const connectorId of chargingStation.connectors.keys()) { + chargingStation.ocppRequestService + .requestHandler< + OCPP16StatusNotificationRequest, + OCPP16StatusNotificationResponse + >( + chargingStation, + OCPP16RequestCommand.STATUS_NOTIFICATION, + { + connectorId, + errorCode: OCPP16ChargePointErrorCode.NO_ERROR, + status: chargingStation.getConnectorStatus(connectorId)?.status, + }, + { + triggerMessage: true, + } + ) + .catch(Constants.EMPTY_FUNCTION); + } } } - }, Constants.OCPP_TRIGGER_MESSAGE_DELAY); - return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; + }, OCPP16Constants.OCPP_TRIGGER_MESSAGE_DELAY); + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; default: - return OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED; + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED; } } catch (error) { return this.handleIncomingRequestError( chargingStation, OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, error as Error, - { errorResponse: OCPPConstants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED } + { errorResponse: OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED } ); } } @@ -1411,7 +1500,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation, OCPP16IncomingRequestCommand.DATA_TRANSFER, error as Error, - { errorResponse: OCPPConstants.OCPP_DATA_TRANSFER_RESPONSE_REJECTED } + { errorResponse: OCPP16Constants.OCPP_DATA_TRANSFER_RESPONSE_REJECTED } ); } }