X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2F1.6%2FOCCP16IncomingRequestService.ts;h=14a8b97d928df3e29f98ea884a1909517f85347d;hb=f6f5fcf76fe58ae58c9891717c4474e72a9bbb0a;hp=f94f410b948a6ef335ca61cdf01f89adec82c084;hpb=e268356bed036cbf1485fc35f60ebf9f511636b0;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts index f94f410b..14a8b97d 100644 --- a/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCCP16IncomingRequestService.ts @@ -1,9 +1,10 @@ import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests'; -import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, DefaultResponse, GetConfigurationResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/RequestResponses'; +import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, GetConfigurationResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/Responses'; import { ChargingProfilePurposeType, OCPP16ChargingProfile } from '../../../types/ocpp/1.6/ChargingProfile'; import { OCPP16AuthorizationStatus, OCPP16StopTransactionReason } from '../../../types/ocpp/1.6/Transaction'; import Constants from '../../../utils/Constants'; +import { DefaultResponse } from '../../../types/ocpp/Responses'; import { ErrorType } from '../../../types/ocpp/ErrorType'; import { MessageType } from '../../../types/ocpp/MessageType'; import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus'; @@ -17,15 +18,16 @@ import logger from '../../../utils/Logger'; export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService { public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record): Promise { let response; + const methodName = `handleRequest${commandName}`; // Call - if (typeof this['handleRequest' + commandName] === 'function') { + if (typeof this[methodName] === 'function') { try { // Call the method to build the response - response = await this['handleRequest' + commandName](commandPayload); + response = await this[methodName](commandPayload); } catch (error) { // Log logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error); - // Send back response to inform backend + // Send back an error response to inform backend await this.chargingStation.ocppRequestService.sendError(messageId, error, commandName); throw error; } @@ -40,10 +42,11 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer // Simulate charging station restart private handleRequestReset(commandPayload: ResetRequest): DefaultResponse { - setImmediate(async () => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises + setImmediate(async (): Promise => { await this.chargingStation.stop(commandPayload.type + 'Reset' as OCPP16StopTransactionReason); await Utils.sleep(this.chargingStation.stationInfo.resetTime); - await this.chargingStation.start(); + this.chargingStation.start(); }); logger.info(`${this.chargingStation.logPrefix()} ${commandPayload.type} reset command received, simulating it. The station will be back online in ${Utils.milliSecondsToHHMMSS(this.chargingStation.stationInfo.resetTime)}`); return Constants.OCPP_RESPONSE_ACCEPTED; @@ -61,7 +64,10 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } if (this.chargingStation.getConnector(connectorId)?.transactionStarted) { const transactionId = this.chargingStation.getConnector(connectorId).transactionId; - const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getTransactionMeterStop(transactionId), this.chargingStation.getTransactionIdTag(transactionId), OCPP16StopTransactionReason.UNLOCK_COMMAND); + const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, + this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), + this.chargingStation.getTransactionIdTag(transactionId), + OCPP16StopTransactionReason.UNLOCK_COMMAND); if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { return Constants.OCPP_RESPONSE_UNLOCKED; } @@ -159,7 +165,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer private handleRequestSetChargingProfile(commandPayload: SetChargingProfileRequest): SetChargingProfileResponse { if (!this.chargingStation.getConnector(commandPayload.connectorId)) { - logger.error(`${this.chargingStation.logPrefix()} Trying to set a charging profile to a non existing connector Id ${commandPayload.connectorId}`); + logger.error(`${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`); return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; } if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE && commandPayload.connectorId !== 0) { @@ -169,23 +175,25 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; } this.chargingStation.setChargingProfile(commandPayload.connectorId, commandPayload.csChargingProfiles); + logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles); return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED; } private handleRequestClearChargingProfile(commandPayload: ClearChargingProfileRequest): ClearChargingProfileResponse { if (!this.chargingStation.getConnector(commandPayload.connectorId)) { - logger.error(`${this.chargingStation.logPrefix()} Trying to clear a charging profile to a non existing connector Id ${commandPayload.connectorId}`); + logger.error(`${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`); return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; } if (commandPayload.connectorId && !Utils.isEmptyArray(this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles)) { this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles = []; + logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles); return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED; } if (!commandPayload.connectorId) { let clearedCP = false; for (const connector in this.chargingStation.connectors) { if (!Utils.isEmptyArray(this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles)) { - this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => { + this.chargingStation.getConnector(Utils.convertToInt(connector)).chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => { let clearCurrentCP = false; if (chargingProfile.chargingProfileId === commandPayload.id) { clearCurrentCP = true; @@ -201,6 +209,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } if (clearCurrentCP) { this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles[index] = {} as OCPP16ChargingProfile; + logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnector(commandPayload.connectorId).chargingProfiles); clearedCP = true; } }); @@ -247,49 +256,76 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise { - const transactionConnectorID: number = commandPayload.connectorId ? commandPayload.connectorId : 1; - if (this.chargingStation.isChargingStationAvailable() && this.chargingStation.isConnectorAvailable(transactionConnectorID)) { - if (this.chargingStation.getAuthorizeRemoteTxRequests() && this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()) { - // Check if authorized - if (this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) { - await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.PREPARING); - this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.PREPARING; - if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) { - this.chargingStation.setChargingProfile(transactionConnectorID, commandPayload.chargingProfile); - } else if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) { - return Constants.OCPP_RESPONSE_REJECTED; + const transactionConnectorId: number = commandPayload.connectorId; + if (transactionConnectorId) { + await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorId, OCPP16ChargePointStatus.PREPARING); + this.chargingStation.getConnector(transactionConnectorId).status = OCPP16ChargePointStatus.PREPARING; + if (this.chargingStation.isChargingStationAvailable() && this.chargingStation.isConnectorAvailable(transactionConnectorId)) { + if (this.chargingStation.getAuthorizeRemoteTxRequests()) { + let authorized = false; + // Check if authorized + if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags() + && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) { + authorized = true; } - // Authorization successful start transaction - await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorID, commandPayload.idTag); - logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_ACCEPTED; + if (!authorized || (authorized && this.chargingStation.getMayAuthorizeAtRemoteStart())) { + const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(transactionConnectorId, commandPayload.idTag); + if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { + authorized = true; + } else { + authorized = false; + } + } + if (authorized) { + // Authorization successful, start transaction + await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag); + logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag); + return await this.setRemoteStartChargingProfile(transactionConnectorId, commandPayload.chargingProfile) + ? Constants.OCPP_RESPONSE_ACCEPTED + : await this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag); + } + return await this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag); } - logger.error(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_REJECTED; + // No authorization check required, start transaction + await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag); + logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag); + return await this.setRemoteStartChargingProfile(transactionConnectorId, commandPayload.chargingProfile) + ? Constants.OCPP_RESPONSE_ACCEPTED + : await this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag); } - await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorID, OCPP16ChargePointStatus.PREPARING); - this.chargingStation.getConnector(transactionConnectorID).status = OCPP16ChargePointStatus.PREPARING; - if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) { - this.chargingStation.setChargingProfile(transactionConnectorID, commandPayload.chargingProfile); - } else if (commandPayload.chargingProfile && commandPayload.chargingProfile.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) { - return Constants.OCPP_RESPONSE_REJECTED; - } - // No local authorization check required => start transaction - await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorID, commandPayload.idTag); - logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorID.toString() + ' for idTag ' + commandPayload.idTag); - return Constants.OCPP_RESPONSE_ACCEPTED; + return await this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag); } - logger.error(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on unavailable connector Id ' + transactionConnectorID.toString() + ', idTag ' + commandPayload.idTag); + return await this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag); + } + + private async notifyRemoteStartTransactionRejected(connectorId: number, idTag: string): Promise { + await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE); + this.chargingStation.getConnector(connectorId).status = OCPP16ChargePointStatus.AVAILABLE; + logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + connectorId.toString() + ', availability ' + this.chargingStation.getConnector(connectorId).availability + ', idTag ' + idTag); return Constants.OCPP_RESPONSE_REJECTED; } + private async setRemoteStartChargingProfile(connectorId: number, cp: OCPP16ChargingProfile): Promise { + if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) { + this.chargingStation.setChargingProfile(connectorId, cp); + logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnector(connectorId).chargingProfiles); + return true; + } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) { + await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE); + this.chargingStation.getConnector(connectorId).status = OCPP16ChargePointStatus.AVAILABLE; + logger.warn(`${this.chargingStation.logPrefix()} Not allowed to set ${cp.chargingProfilePurpose} charging profile(s) at remote start transaction`); + return false; + } + } + private async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise { const transactionId = commandPayload.transactionId; for (const connector in this.chargingStation.connectors) { if (Utils.convertToInt(connector) > 0 && this.chargingStation.getConnector(Utils.convertToInt(connector))?.transactionId === transactionId) { await this.chargingStation.ocppRequestService.sendStatusNotification(Utils.convertToInt(connector), OCPP16ChargePointStatus.FINISHING); this.chargingStation.getConnector(Utils.convertToInt(connector)).status = OCPP16ChargePointStatus.FINISHING; - await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getTransactionMeterStop(transactionId), this.chargingStation.getTransactionIdTag(transactionId)); + await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), + this.chargingStation.getTransactionIdTag(transactionId)); return Constants.OCPP_RESPONSE_ACCEPTED; } }