X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2Focpp%2F1.6%2FOCPP16IncomingRequestService.ts;h=773d01e318c267fc52b6ec54d61f32b626bbf8a4;hb=382b62c45d665e66d4a2f3ad5ac7ecc6396859c7;hp=7f932cb0e19165e65899f8265f5f7763ce415821;hpb=ceb9a9009db1987092c2bdf8266118913a6965a4;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 7f932cb0..773d01e3 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -1,26 +1,26 @@ // Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved. +import { randomInt } from 'node:crypto' import { createWriteStream, readdirSync } from 'node:fs' -import { dirname, join, resolve } from 'node:path' -import { URL, fileURLToPath } from 'node:url' +import { dirname, extname, join, resolve } from 'node:path' +import { fileURLToPath, URL } from 'node:url' import type { ValidateFunction } from 'ajv' import { Client, type FTPResponse } from 'basic-ftp' import { - type Interval, addSeconds, differenceInSeconds, + type Interval, isDate, secondsToMilliseconds } from 'date-fns' import { maxTime } from 'date-fns/constants' +import { isEmpty } from 'rambda' import { create } from 'tar' -import { OCPP16Constants } from './OCPP16Constants.js' -import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js' import { - type ChargingStation, canProceedChargingProfile, + type ChargingStation, checkChargingStation, getConfigurationKey, getConnectorChargingProfiles, @@ -32,6 +32,7 @@ import { OCPPError } from '../../../exception/index.js' import { type ChangeConfigurationRequest, type ChangeConfigurationResponse, + ConfigurationSection, ErrorType, type GenericResponse, GenericStatus, @@ -41,6 +42,7 @@ import { type GetDiagnosticsResponse, type IncomingRequestHandler, type JsonType, + type LogConfiguration, OCPP16AuthorizationStatus, OCPP16AvailabilityType, type OCPP16BootNotificationRequest, @@ -83,6 +85,7 @@ import { OCPP16SupportedFeatureProfiles, type OCPP16TriggerMessageRequest, type OCPP16TriggerMessageResponse, + OCPP16TriggerMessageStatus, type OCPP16UpdateFirmwareRequest, type OCPP16UpdateFirmwareResponse, type OCPPConfigurationKey, @@ -97,18 +100,20 @@ import { type UnlockConnectorResponse } from '../../../types/index.js' import { + Configuration, Constants, convertToDate, convertToInt, formatDurationMilliSeconds, - getRandomInteger, - isEmptyArray, + isAsyncFunction, isNotEmptyArray, isNotEmptyString, logger, sleep } from '../../../utils/index.js' import { OCPPIncomingRequestService } from '../OCPPIncomingRequestService.js' +import { OCPP16Constants } from './OCPP16Constants.js' +import { OCPP16ServiceUtils } from './OCPP16ServiceUtils.js' const moduleName = 'OCPP16IncomingRequestService' @@ -404,137 +409,191 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { .bind(this) ] ]) + // Handle incoming request events this.on( OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION, - (chargingStation: ChargingStation, connectorId: number, idTag: string) => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - chargingStation.getConnectorStatus(connectorId)!.transactionRemoteStarted = true - chargingStation.ocppRequestService - .requestHandler( - chargingStation, - OCPP16RequestCommand.START_TRANSACTION, - { - connectorId, - idTag - } - ) - .then(response => { - if (response.status === OCPP16AuthorizationStatus.ACCEPTED) { - logger.debug( - `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for idTag '${idTag}'` - ) - } else { - logger.debug( - `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${chargingStation.stationInfo?.chargingStationId}#${connectorId} for idTag '${idTag}'` - ) + ( + chargingStation: ChargingStation, + request: RemoteStartTransactionRequest, + response: GenericResponse + ) => { + if (response.status === GenericStatus.Accepted) { + const { connectorId, idTag } = request + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + chargingStation.getConnectorStatus(connectorId!)!.transactionRemoteStarted = true + chargingStation.ocppRequestService + .requestHandler, OCPP16StartTransactionResponse>( + chargingStation, + OCPP16RequestCommand.START_TRANSACTION, + { + connectorId, + idTag } - }) - .catch(error => { - logger.error( - `${chargingStation.logPrefix()} ${moduleName}.constructor: Remote start transaction error:`, - error - ) - }) + ) + .then(response => { + if (response.status === OCPP16AuthorizationStatus.ACCEPTED) { + logger.debug( + `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${ + chargingStation.stationInfo?.chargingStationId + }#${connectorId} for idTag '${idTag}'` + ) + } else { + logger.debug( + `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${ + chargingStation.stationInfo?.chargingStationId + }#${connectorId} for idTag '${idTag}'` + ) + } + }) + .catch((error: unknown) => { + logger.error( + `${chargingStation.logPrefix()} ${moduleName}.constructor: Remote start transaction error:`, + error + ) + }) + } } ) this.on( - `Trigger${OCPP16MessageTrigger.BootNotification}`, - (chargingStation: ChargingStation) => { - chargingStation.ocppRequestService - .requestHandler( - chargingStation, - OCPP16RequestCommand.BOOT_NOTIFICATION, - chargingStation.bootNotificationRequest, - { skipBufferingOnError: true, triggerMessage: true } - ) - .then(response => { - chargingStation.bootNotificationResponse = response - }) - .catch(error => { - logger.error( - `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger boot notification error:`, - error - ) - }) + OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION, + ( + chargingStation: ChargingStation, + request: RemoteStopTransactionRequest, + response: GenericResponse + ) => { + if (response.status === GenericStatus.Accepted) { + const { transactionId } = request + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const connectorId = chargingStation.getConnectorIdByTransactionId(transactionId)! + OCPP16ServiceUtils.remoteStopTransaction(chargingStation, connectorId) + .then(response => { + if (response.status === GenericStatus.Accepted) { + logger.debug( + `${chargingStation.logPrefix()} Remote stop transaction ACCEPTED on ${ + chargingStation.stationInfo?.chargingStationId + }#${connectorId} for transaction '${transactionId}'` + ) + } else { + logger.debug( + `${chargingStation.logPrefix()} Remote stop transaction REJECTED on ${ + chargingStation.stationInfo?.chargingStationId + }#${connectorId} for transaction '${transactionId}'` + ) + } + }) + .catch((error: unknown) => { + logger.error( + `${chargingStation.logPrefix()} ${moduleName}.constructor: Remote stop transaction error:`, + error + ) + }) + } } ) - this.on(`Trigger${OCPP16MessageTrigger.Heartbeat}`, (chargingStation: ChargingStation) => { - chargingStation.ocppRequestService - .requestHandler( - chargingStation, - OCPP16RequestCommand.HEARTBEAT, - undefined, - { - triggerMessage: true - } - ) - .catch(error => { - logger.error( - `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger heartbeat error:`, - error - ) - }) - }) this.on( - `$Trigger${OCPP16MessageTrigger.StatusNotification}`, - (chargingStation: ChargingStation, connectorId?: number) => { - const errorHandler = (error: Error): void => { + OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, + ( + chargingStation: ChargingStation, + request: OCPP16TriggerMessageRequest, + response: OCPP16TriggerMessageResponse + ) => { + if (response.status !== OCPP16TriggerMessageStatus.ACCEPTED) { + return + } + const { requestedMessage, connectorId } = request + const errorHandler = (error: unknown): void => { logger.error( - `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger status notification error:`, + `${chargingStation.logPrefix()} ${moduleName}.constructor: Trigger ${requestedMessage} error:`, error ) } - if (connectorId != null) { - chargingStation.ocppRequestService - .requestHandler( - chargingStation, - OCPP16RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - status: chargingStation.getConnectorStatus(connectorId)?.status - }, - { - triggerMessage: true - } - ) - .catch(errorHandler) - } else if (chargingStation.hasEvses) { - for (const evseStatus of chargingStation.evses.values()) { - for (const [id, connectorStatus] of evseStatus.connectors) { + switch (requestedMessage) { + case OCPP16MessageTrigger.BootNotification: + chargingStation.ocppRequestService + .requestHandler( + chargingStation, + OCPP16RequestCommand.BOOT_NOTIFICATION, + chargingStation.bootNotificationRequest as OCPP16BootNotificationRequest, + { skipBufferingOnError: true, triggerMessage: true } + ) + .then(response => { + chargingStation.bootNotificationResponse = response + }) + .catch(errorHandler) + break + case OCPP16MessageTrigger.Heartbeat: + chargingStation.ocppRequestService + .requestHandler( + chargingStation, + OCPP16RequestCommand.HEARTBEAT, + undefined, + { + triggerMessage: true + } + ) + .catch(errorHandler) + break + case OCPP16MessageTrigger.StatusNotification: + if (connectorId != null) { chargingStation.ocppRequestService .requestHandler( chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { - connectorId: id, + connectorId, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - status: connectorStatus.status + status: chargingStation.getConnectorStatus(connectorId) + ?.status as OCPP16ChargePointStatus }, { triggerMessage: true } ) .catch(errorHandler) - } - } - } else { - for (const [id, connectorStatus] of chargingStation.connectors) { - chargingStation.ocppRequestService - .requestHandler( - chargingStation, - OCPP16RequestCommand.STATUS_NOTIFICATION, - { - connectorId: id, - errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - status: connectorStatus.status - }, - { - triggerMessage: true + } else if (chargingStation.hasEvses) { + for (const evseStatus of chargingStation.evses.values()) { + for (const [id, connectorStatus] of evseStatus.connectors) { + chargingStation.ocppRequestService + .requestHandler< + OCPP16StatusNotificationRequest, + OCPP16StatusNotificationResponse + >( + chargingStation, + OCPP16RequestCommand.STATUS_NOTIFICATION, + { + connectorId: id, + errorCode: OCPP16ChargePointErrorCode.NO_ERROR, + status: connectorStatus.status as OCPP16ChargePointStatus + }, + { + triggerMessage: true + } + ) + .catch(errorHandler) + } } - ) - .catch(errorHandler) - } + } else { + for (const [id, connectorStatus] of chargingStation.connectors) { + chargingStation.ocppRequestService + .requestHandler< + OCPP16StatusNotificationRequest, + OCPP16StatusNotificationResponse + >( + chargingStation, + OCPP16RequestCommand.STATUS_NOTIFICATION, + { + connectorId: id, + errorCode: OCPP16ChargePointErrorCode.NO_ERROR, + status: connectorStatus.status as OCPP16ChargePointStatus + }, + { + triggerMessage: true + } + ) + .catch(errorHandler) + } + } + break } } ) @@ -578,10 +637,12 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { this.validatePayload(chargingStation, commandName, commandPayload) // Call the method to build the response // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - response = (await this.incomingRequestHandlers.get(commandName)!( - chargingStation, - commandPayload - )) as ResType + const incomingRequestHandler = this.incomingRequestHandlers.get(commandName)! + if (isAsyncFunction(incomingRequestHandler)) { + response = (await incomingRequestHandler(chargingStation, commandPayload)) as ResType + } else { + response = incomingRequestHandler(chargingStation, commandPayload) as ResType + } } catch (error) { // Log logger.error( @@ -594,7 +655,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { // Throw exception throw new OCPPError( ErrorType.NOT_IMPLEMENTED, - `${commandName} is not implemented to handle request PDU ${JSON.stringify( + `'${commandName}' is not implemented to handle request PDU ${JSON.stringify( commandPayload, undefined, 2 @@ -610,7 +671,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { commandPayload, undefined, 2 - )} while the charging station is not registered on the central server.`, + )} while the charging station is not registered on the central server`, commandName, commandPayload ) @@ -622,6 +683,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { response, commandName ) + // Emit command name event to allow delayed handling + this.emit(commandName, chargingStation, commandPayload, response) } private validatePayload ( @@ -889,8 +952,8 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { } const connectorStatus = chargingStation.getConnectorStatus(connectorId) if ( - isEmptyArray(connectorStatus?.chargingProfiles) && - isEmptyArray(chargingStation.getConnectorStatus(0)?.chargingProfiles) + isEmpty(connectorStatus?.chargingProfiles) && + isEmpty(chargingStation.getConnectorStatus(0)?.chargingProfiles) ) { return OCPP16Constants.OCPP_RESPONSE_REJECTED } @@ -990,41 +1053,46 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN } const { connectorId } = commandPayload - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - if (!chargingStation.hasConnector(connectorId!)) { - logger.error( - `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${connectorId}` - ) - return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN - } - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const connectorStatus = chargingStation.getConnectorStatus(connectorId!) - if (connectorId != null && isNotEmptyArray(connectorStatus?.chargingProfiles)) { - connectorStatus.chargingProfiles = [] - logger.debug( - `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${connectorId}` - ) - return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED - } - if (connectorId == null) { + if (connectorId != null) { + if (!chargingStation.hasConnector(connectorId)) { + logger.error( + `${chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector id ${connectorId}` + ) + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN + } + const connectorStatus = chargingStation.getConnectorStatus(connectorId) + if (isNotEmptyArray(connectorStatus?.chargingProfiles)) { + connectorStatus.chargingProfiles = [] + logger.debug( + `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${connectorId}` + ) + return OCPP16Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED + } + } else { let clearedCP = false if (chargingStation.hasEvses) { for (const evseStatus of chargingStation.evses.values()) { for (const status of evseStatus.connectors.values()) { - clearedCP = OCPP16ServiceUtils.clearChargingProfiles( + const clearedConnectorCP = OCPP16ServiceUtils.clearChargingProfiles( chargingStation, commandPayload, status.chargingProfiles ) + if (clearedConnectorCP && !clearedCP) { + clearedCP = true + } } } } else { for (const id of chargingStation.connectors.keys()) { - clearedCP = OCPP16ServiceUtils.clearChargingProfiles( + const clearedConnectorCP = OCPP16ServiceUtils.clearChargingProfiles( chargingStation, commandPayload, chargingStation.getConnectorStatus(id)?.chargingProfiles ) + if (clearedConnectorCP && !clearedCP) { + clearedCP = true + } } } if (clearedCP) { @@ -1097,9 +1165,22 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation: ChargingStation, commandPayload: RemoteStartTransactionRequest ): Promise { + if (commandPayload.connectorId == null) { + do { + commandPayload.connectorId = randomInt(1, chargingStation.getNumberOfConnectors()) + } while ( + chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted === + true && + OCPP16ServiceUtils.hasReservation( + chargingStation, + commandPayload.connectorId, + commandPayload.idTag + ) + ) + } const { connectorId: transactionConnectorId, idTag, chargingProfile } = commandPayload if (!chargingStation.hasConnector(transactionConnectorId)) { - return await this.notifyRemoteStartTransactionRejected( + return this.notifyRemoteStartTransactionRejected( chargingStation, transactionConnectorId, idTag @@ -1109,7 +1190,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { !chargingStation.isChargingStationAvailable() || !chargingStation.isConnectorAvailable(transactionConnectorId) ) { - return await this.notifyRemoteStartTransactionRejected( + return this.notifyRemoteStartTransactionRejected( chargingStation, transactionConnectorId, idTag @@ -1120,17 +1201,12 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.getAuthorizeRemoteTxRequests() && !(await OCPP16ServiceUtils.isIdTagAuthorized(chargingStation, transactionConnectorId, idTag)) ) { - return await this.notifyRemoteStartTransactionRejected( + return this.notifyRemoteStartTransactionRejected( chargingStation, transactionConnectorId, idTag ) } - await OCPP16ServiceUtils.sendAndSetConnectorStatus( - chargingStation, - transactionConnectorId, - OCPP16ChargePointStatus.Preparing - ) if ( chargingProfile != null && !this.setRemoteStartTransactionChargingProfile( @@ -1139,40 +1215,32 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingProfile ) ) { - return await this.notifyRemoteStartTransactionRejected( + return this.notifyRemoteStartTransactionRejected( chargingStation, transactionConnectorId, idTag ) } - Promise.resolve() - .then(() => - this.emit( - OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION, - chargingStation, - transactionConnectorId, - idTag - ) - ) - .catch(Constants.EMPTY_FUNCTION) + logger.debug( + `${chargingStation.logPrefix()} Remote start transaction ACCEPTED on ${ + chargingStation.stationInfo?.chargingStationId + }#${transactionConnectorId}}, idTag '${idTag}'` + ) return OCPP16Constants.OCPP_RESPONSE_ACCEPTED } - private async notifyRemoteStartTransactionRejected ( + private notifyRemoteStartTransactionRejected ( chargingStation: ChargingStation, connectorId: number, idTag: string - ): Promise { + ): GenericResponse { const connectorStatus = chargingStation.getConnectorStatus(connectorId) - if (connectorStatus?.status !== OCPP16ChargePointStatus.Available) { - await OCPP16ServiceUtils.sendAndSetConnectorStatus( - chargingStation, - connectorId, - OCPP16ChargePointStatus.Available - ) - } - logger.warn( - `${chargingStation.logPrefix()} Remote start transaction REJECTED on connector id ${connectorId}, idTag '${idTag}', availability '${connectorStatus?.availability}', status '${connectorStatus?.status}'` + logger.debug( + `${chargingStation.logPrefix()} Remote start transaction REJECTED on ${ + chargingStation.stationInfo?.chargingStationId + }#${connectorId}, idTag '${idTag}', availability '${ + connectorStatus?.availability + }', status '${connectorStatus?.status}'` ) return OCPP16Constants.OCPP_RESPONSE_REJECTED } @@ -1185,12 +1253,14 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { if (chargingProfile.chargingProfilePurpose === OCPP16ChargingProfilePurposeType.TX_PROFILE) { OCPP16ServiceUtils.setChargingProfile(chargingStation, connectorId, chargingProfile) logger.debug( - `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}: %j`, + `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on ${ + chargingStation.stationInfo?.chargingStationId + }#${connectorId}`, chargingProfile ) return true } - logger.warn( + logger.debug( `${chargingStation.logPrefix()} Not allowed to set ${ chargingProfile.chargingProfilePurpose } charging profile(s) at remote start transaction` @@ -1198,33 +1268,19 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { return false } - private async handleRequestRemoteStopTransaction ( + private handleRequestRemoteStopTransaction ( chargingStation: ChargingStation, commandPayload: RemoteStopTransactionRequest - ): Promise { + ): GenericResponse { const { transactionId } = commandPayload - 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 await OCPP16ServiceUtils.remoteStopTransaction(chargingStation, connectorId) - } - } - } - } - } else { - for (const connectorId of chargingStation.connectors.keys()) { - if ( - connectorId > 0 && - chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId - ) { - return await OCPP16ServiceUtils.remoteStopTransaction(chargingStation, connectorId) - } - } + if (chargingStation.getConnectorIdByTransactionId(transactionId) != null) { + logger.debug( + `${chargingStation.logPrefix()} Remote stop transaction ACCEPTED for transactionId '${transactionId}'` + ) + return OCPP16Constants.OCPP_RESPONSE_ACCEPTED } - logger.warn( - `${chargingStation.logPrefix()} Trying to remote stop a non existing transaction with id ${transactionId}` + logger.debug( + `${chargingStation.logPrefix()} Remote stop transaction REJECTED for transactionId '${transactionId}'` ) return OCPP16Constants.OCPP_RESPONSE_REJECTED } @@ -1248,7 +1304,10 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion commandPayload.retrieveDate = convertToDate(commandPayload.retrieveDate)! const { retrieveDate } = commandPayload - if (chargingStation.stationInfo?.firmwareStatus !== OCPP16FirmwareStatus.Installed) { + if ( + chargingStation.stationInfo?.firmwareStatus != null && + chargingStation.stationInfo.firmwareStatus !== OCPP16FirmwareStatus.Installed + ) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.handleRequestUpdateFirmware: Cannot simulate firmware update: firmware update is already in progress` ) @@ -1313,7 +1372,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.stationInfo?.firmwareUpgrade?.failureStatus === OCPP16FirmwareStatus.DownloadFailed ) { - await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay))) + await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay))) await chargingStation.ocppRequestService.requestHandler< OCPP16FirmwareStatusNotificationRequest, OCPP16FirmwareStatusNotificationResponse @@ -1324,7 +1383,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.stationInfo.firmwareUpgrade.failureStatus return } - await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay))) + await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay))) await chargingStation.ocppRequestService.requestHandler< OCPP16FirmwareStatusNotificationRequest, OCPP16FirmwareStatusNotificationResponse @@ -1380,8 +1439,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { transactionsStarted = false } } while (transactionsStarted) - !wasTransactionsStarted && - (await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay)))) + !wasTransactionsStarted && (await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay)))) if (!checkChargingStation(chargingStation, chargingStation.logPrefix())) { return } @@ -1397,7 +1455,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation.stationInfo?.firmwareUpgrade?.failureStatus === OCPP16FirmwareStatus.InstallationFailed ) { - await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay))) + await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay))) await chargingStation.ocppRequestService.requestHandler< OCPP16FirmwareStatusNotificationRequest, OCPP16FirmwareStatusNotificationResponse @@ -1409,7 +1467,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { return } if (chargingStation.stationInfo?.firmwareUpgrade?.reset === true) { - await sleep(secondsToMilliseconds(getRandomInteger(maxDelay, minDelay))) + await sleep(secondsToMilliseconds(randomInt(minDelay, maxDelay))) await chargingStation.reset(OCPP16StopTransactionReason.REBOOT) } } @@ -1435,14 +1493,22 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { if (uri.protocol.startsWith('ftp:')) { let ftpClient: Client | undefined try { - const logFiles = readdirSync(resolve(dirname(fileURLToPath(import.meta.url)), '../')) - .filter(file => file.endsWith('.log')) - .map(file => join('./', file)) + const logConfiguration = Configuration.getConfigurationSection( + ConfigurationSection.log + ) + const logFiles = readdirSync( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + resolve((fileURLToPath(import.meta.url), '../', dirname(logConfiguration.file!))) + ) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + .filter(file => file.endsWith(extname(logConfiguration.file!))) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + .map(file => join(dirname(logConfiguration.file!), file)) const diagnosticsArchive = `${chargingStation.stationInfo?.chargingStationId}_logs.tar.gz` create({ gzip: true }, logFiles).pipe(createWriteStream(diagnosticsArchive)) ftpClient = new Client() const accessResponse = await ftpClient.access({ - host: uri.host, + host: uri.hostname, ...(isNotEmptyString(uri.port) && { port: convertToInt(uri.port) }), ...(isNotEmptyString(uri.username) && { user: uri.username }), ...(isNotEmptyString(uri.password) && { password: uri.password }) @@ -1462,7 +1528,7 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.Uploading }) - .catch(error => { + .catch((error: unknown) => { logger.error( `${chargingStation.logPrefix()} ${moduleName}.handleRequestGetDiagnostics: Error while sending '${ OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION @@ -1553,42 +1619,13 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { ) { return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED } - try { - switch (requestedMessage) { - case OCPP16MessageTrigger.BootNotification: - Promise.resolve() - .then(() => - this.emit(`Trigger${OCPP16MessageTrigger.BootNotification}`, chargingStation) - ) - .catch(Constants.EMPTY_FUNCTION) - return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED - case OCPP16MessageTrigger.Heartbeat: - Promise.resolve() - .then(() => this.emit(`Trigger${OCPP16MessageTrigger.Heartbeat}`, chargingStation)) - .catch(Constants.EMPTY_FUNCTION) - return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED - case OCPP16MessageTrigger.StatusNotification: - Promise.resolve() - .then(() => - this.emit( - `Trigger${OCPP16MessageTrigger.StatusNotification}`, - chargingStation, - connectorId - ) - ) - .catch(Constants.EMPTY_FUNCTION) - return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED - default: - return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED - } - } catch (error) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return this.handleIncomingRequestError( - chargingStation, - OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, - error as Error, - { errorResponse: OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED } - )! + switch (requestedMessage) { + case OCPP16MessageTrigger.BootNotification: + case OCPP16MessageTrigger.Heartbeat: + case OCPP16MessageTrigger.StatusNotification: + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED + default: + return OCPP16Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED } } @@ -1720,7 +1757,9 @@ export class OCPP16IncomingRequestService extends OCPPIncomingRequestService { chargingStation, OCPP16IncomingRequestCommand.CANCEL_RESERVATION, error as Error, - { errorResponse: OCPP16Constants.OCPP_CANCEL_RESERVATION_RESPONSE_REJECTED } + { + errorResponse: OCPP16Constants.OCPP_CANCEL_RESERVATION_RESPONSE_REJECTED + } )! } }