X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2F1.6%2FOCPP16IncomingRequestService.ts;h=7a2a3cb8be57b15c21fd41f86f567298d584438e;hb=2585c6e94e3d900bf7ecca428299df1e649252db;hp=8b23eddd1e0820c118a8b8242aaa31f413fe7353;hpb=b768993dd4636df8276b0ea47158dd9bdc9a997b;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 8b23eddd..7a2a3cb8 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -23,6 +23,7 @@ import { type ClearChargingProfileResponse, ErrorType, type GenericResponse, + GenericStatus, type GetConfigurationRequest, type GetConfigurationResponse, type GetDiagnosticsRequest, @@ -40,6 +41,7 @@ import { OCPP16ChargePointStatus, type OCPP16ChargingProfile, OCPP16ChargingProfilePurposeType, + type OCPP16ChargingSchedule, type OCPP16ClearCacheRequest, type OCPP16DataTransferRequest, type OCPP16DataTransferResponse, @@ -51,6 +53,8 @@ import { OCPP16FirmwareStatus, type OCPP16FirmwareStatusNotificationRequest, type OCPP16FirmwareStatusNotificationResponse, + type OCPP16GetCompositeScheduleRequest, + type OCPP16GetCompositeScheduleResponse, type OCPP16HeartbeatRequest, type OCPP16HeartbeatResponse, OCPP16IncomingRequestCommand, @@ -78,7 +82,7 @@ import { type UnlockConnectorResponse, } from '../../../types'; import { Constants, Utils, logger } from '../../../utils'; -import { OCPP16ServiceUtils, OCPPConstants, OCPPIncomingRequestService } from '../internal'; +import { OCPP16Constants, OCPP16ServiceUtils, OCPPIncomingRequestService } from '../internal'; const moduleName = 'OCPP16IncomingRequestService'; @@ -103,6 +107,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION, this.handleRequestChangeConfiguration.bind(this), ], + [ + OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE, + this.handleRequestGetCompositeSchedule.bind(this), + ], [ OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE, this.handleRequestSetChargingProfile.bind(this), @@ -177,6 +185,14 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { 'constructor' ), ], + [ + OCPP16IncomingRequestCommand.GET_COMPOSITE_SCHEDULE, + OCPP16ServiceUtils.parseJsonSchemaFile( + '../../../assets/json-schemas/ocpp/1.6/GetCompositeSchedule.json', + moduleName, + 'constructor' + ), + ], [ OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE, OCPP16ServiceUtils.parseJsonSchemaFile( @@ -242,7 +258,11 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ), ], ]); - this.validatePayload.bind(this); + this.validatePayload = this.validatePayload.bind(this) as ( + chargingStation: ChargingStation, + commandName: OCPP16IncomingRequestCommand, + commandPayload: JsonType + ) => boolean; } public async incomingRequestHandler( @@ -366,7 +386,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.stationInfo.resetTime )}` ); - return OCPPConstants.OCPP_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED; } private async handleRequestUnlockConnector( @@ -376,15 +396,15 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { const connectorId = commandPayload.connectorId; if (chargingStation.connectors.has(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( @@ -392,20 +412,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 chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, connectorId, - status: OCPP16ChargePointStatus.Available, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); - chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Available; - return OCPPConstants.OCPP_RESPONSE_UNLOCKED; + OCPP16ChargePointStatus.Available + ); + return OCPP16Constants.OCPP_RESPONSE_UNLOCKED; } private handleRequestGetConfiguration( @@ -468,9 +484,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { true ); if (!keyToChange) { - return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED; + return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED; } else if (keyToChange && keyToChange.readonly) { - return OCPPConstants.OCPP_CONFIGURATION_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_CONFIGURATION_RESPONSE_REJECTED; } else if (keyToChange && !keyToChange.readonly) { let valueChanged = false; if (keyToChange.value !== commandPayload.value) { @@ -506,9 +522,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; } } @@ -523,22 +539,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) { 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 === @@ -552,7 +568,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, @@ -565,7 +581,57 @@ 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( + chargingStation: ChargingStation, + commandPayload: OCPP16GetCompositeScheduleRequest + ): OCPP16GetCompositeScheduleResponse { + if ( + OCPP16ServiceUtils.checkFeatureProfile( + chargingStation, + OCPP16SupportedFeatureProfiles.SmartCharging, + OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE + ) === false + ) { + return OCPP16Constants.OCPP_RESPONSE_REJECTED; + } + if (chargingStation.connectors.has(commandPayload.connectorId) === false) { + logger.error( + `${chargingStation.logPrefix()} Trying to get composite schedule to a non existing connector id ${ + commandPayload.connectorId + }` + ); + return OCPP16Constants.OCPP_RESPONSE_REJECTED; + } + if ( + Utils.isEmptyArray( + chargingStation.getConnectorStatus(commandPayload.connectorId)?.chargingProfiles + ) + ) { + return OCPP16Constants.OCPP_RESPONSE_REJECTED; + } + const startDate = new Date(); + const endDate = new Date(startDate.getTime() + commandPayload.duration * 1000); + let compositeSchedule: OCPP16ChargingSchedule; + for (const chargingProfile of chargingStation.getConnectorStatus(commandPayload.connectorId) + .chargingProfiles) { + // FIXME: build the composite schedule including the local power limit, the stack level, the charging rate unit, etc. + if ( + chargingProfile.chargingSchedule?.startSchedule >= startDate && + chargingProfile.chargingSchedule?.startSchedule <= endDate + ) { + compositeSchedule = chargingProfile.chargingSchedule; + break; + } + } + return { + status: GenericStatus.Accepted, + scheduleStart: compositeSchedule?.startSchedule, + connectorId: commandPayload.connectorId, + chargingSchedule: compositeSchedule, + }; } private handleRequestClearChargingProfile( @@ -579,15 +645,15 @@ 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) { 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 ( @@ -600,7 +666,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { 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; @@ -645,10 +711,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { } } 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( @@ -658,31 +724,28 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { const connectorId: number = commandPayload.connectorId; if (chargingStation.connectors.has(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 ? OCPP16ChargePointStatus.Available : OCPP16ChargePointStatus.Unavailable; if (connectorId === 0) { - let response: ChangeAvailabilityResponse = OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; + let response: ChangeAvailabilityResponse = + OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; for (const id of chargingStation.connectors.keys()) { if (chargingStation.getConnectorStatus(id)?.transactionStarted === true) { - response = OCPPConstants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; + response = OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } chargingStation.getConnectorStatus(id).availability = commandPayload.type; - if (response === OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) { - await chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { - connectorId: id, - status: chargePointStatus, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); - chargingStation.getConnectorStatus(id).status = chargePointStatus; + if (response === OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + id, + chargePointStatus + ); } } return response; @@ -694,21 +757,17 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ) { 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 chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, connectorId, - status: chargePointStatus, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); - chargingStation.getConnectorStatus(connectorId).status = chargePointStatus; - return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; + chargePointStatus + ); + return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; } - return OCPPConstants.OCPP_AVAILABILITY_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED; } private async handleRequestRemoteStartTransaction( @@ -720,28 +779,25 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { const remoteStartTransactionLogMsg = `${chargingStation.logPrefix()} Transaction remotely STARTED on ${ chargingStation.stationInfo.chargingStationId }#${transactionConnectorId.toString()} for idTag '${commandPayload.idTag}'`; - await chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { - connectorId: transactionConnectorId, - status: OCPP16ChargePointStatus.Preparing, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, + transactionConnectorId, + OCPP16ChargePointStatus.Preparing + ); const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId); - connectorStatus.status = OCPP16ChargePointStatus.Preparing; - if (chargingStation.isChargingStationAvailable() === true) { + if ( + chargingStation.isChargingStationAvailable() === true && + chargingStation.isConnectorAvailable(transactionConnectorId) === true + ) { // Check if authorized if (chargingStation.getAuthorizeRemoteTxRequests() === true) { let authorized = false; if ( chargingStation.getLocalAuthListEnabled() === true && - chargingStation.hasAuthorizedTags() === true && + chargingStation.hasIdTags() === true && Utils.isNotEmptyString( - chargingStation.authorizedTagsCache - .getAuthorizedTags( - ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo) - ) + chargingStation.idTagsCache + .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo)) ?.find((idTag) => idTag === commandPayload.idTag) ) ) { @@ -787,7 +843,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, @@ -828,7 +884,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, @@ -863,22 +919,18 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { if ( chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.Available ) { - await chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, connectorId, - status: OCPP16ChargePointStatus.Available, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); - chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Available; + OCPP16ChargePointStatus.Available + ); } 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( @@ -915,29 +967,25 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { connectorId > 0 && chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId ) { - await chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, connectorId, - status: OCPP16ChargePointStatus.Finishing, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); - chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.Finishing; + OCPP16ChargePointStatus.Finishing + ); const stopResponse = await chargingStation.stopTransactionOnConnector( connectorId, OCPP16StopTransactionReason.REMOTE ); if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { - return OCPPConstants.OCPP_RESPONSE_ACCEPTED; + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED; } - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } } logger.warn( `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction ${transactionId.toString()}` ); - return OCPPConstants.OCPP_RESPONSE_REJECTED; + return OCPP16Constants.OCPP_RESPONSE_REJECTED; } private handleRequestUpdateFirmware( @@ -954,7 +1002,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) && @@ -963,13 +1011,13 @@ 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(); if (retrieveDate?.getTime() <= now) { this.runInAsyncScope( - this.updateFirmware.bind(this) as ( + this.updateFirmwareSimulation.bind(this) as ( this: OCPP16IncomingRequestService, ...args: any[] ) => Promise, @@ -978,33 +1026,33 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ).catch(Constants.EMPTY_FUNCTION); } else { setTimeout(() => { - this.updateFirmware(chargingStation).catch(Constants.EMPTY_FUNCTION); + this.updateFirmwareSimulation(chargingStation).catch(Constants.EMPTY_FUNCTION); }, retrieveDate?.getTime() - now); } - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } - private async updateFirmware( + private async updateFirmwareSimulation( chargingStation: ChargingStation, maxDelay = 30, minDelay = 15 ): Promise { - chargingStation.stopAutomaticTransactionGenerator(); + if ( + ChargingStationUtils.checkChargingStation(chargingStation, chargingStation.logPrefix()) === + false + ) { + return; + } for (const connectorId of chargingStation.connectors.keys()) { if ( connectorId > 0 && chargingStation.getConnectorStatus(connectorId)?.transactionStarted === false ) { - await chargingStation.ocppRequestService.requestHandler< - OCPP16StatusNotificationRequest, - OCPP16StatusNotificationResponse - >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { + await OCPP16ServiceUtils.sendAndSetConnectorStatus( + chargingStation, connectorId, - status: OCPP16ChargePointStatus.Unavailable, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - }); - chargingStation.getConnectorStatus(connectorId).status = - OCPP16ChargePointStatus.Unavailable; + OCPP16ChargePointStatus.Unavailable + ); } } await chargingStation.ocppRequestService.requestHandler< @@ -1037,7 +1085,53 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { status: OCPP16FirmwareStatus.Downloaded, }); chargingStation.stationInfo.firmwareStatus = OCPP16FirmwareStatus.Downloaded; - await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000); + 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 waitTime = 15 * 1000; + logger.debug( + `${chargingStation.logPrefix()} ${moduleName}.updateFirmwareSimulation: ${trxCount} transaction(s) in progress, waiting ${ + waitTime / 1000 + } seconds before continuing firmware update simulation` + ); + await Utils.sleep(waitTime); + 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 + ); + } + } + transactionsStarted = false; + } + } while (transactionsStarted); + !wasTransactionsStarted && + (await Utils.sleep(Utils.getRandomInteger(maxDelay, minDelay) * 1000)); + if ( + ChargingStationUtils.checkChargingStation(chargingStation, chargingStation.logPrefix()) === + false + ) { + return; + } await chargingStation.ocppRequestService.requestHandler< OCPP16FirmwareStatusNotificationRequest, OCPP16FirmwareStatusNotificationResponse @@ -1080,7 +1174,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:')) { @@ -1171,7 +1265,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, error as Error, - { errorResponse: OCPPConstants.OCPP_RESPONSE_EMPTY } + { errorResponse: OCPP16Constants.OCPP_RESPONSE_EMPTY } ); } } else { @@ -1186,7 +1280,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.UploadFailed, }); - return OCPPConstants.OCPP_RESPONSE_EMPTY; + return OCPP16Constants.OCPP_RESPONSE_EMPTY; } } @@ -1205,7 +1299,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( @@ -1214,7 +1308,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) { @@ -1231,8 +1325,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 @@ -1245,8 +1339,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)) { @@ -1285,17 +1379,17 @@ 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; 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 } ); } } @@ -1318,7 +1412,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 } ); } }