From 08f130a055123f5e47c59e1a64875f8cff44d020 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Mon, 16 May 2022 22:37:26 +0200 Subject: [PATCH] Untangle ChargingStation class from OCPP services classes MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit And make OCPP services singleton Signed-off-by: Jérôme Benoit --- .../AutomaticTransactionGenerator.ts | 12 +- src/charging-station/ChargingStation.ts | 24 +- .../ocpp/1.6/OCPP16IncomingRequestService.ts | 365 ++++++++++-------- .../ocpp/1.6/OCPP16RequestService.ts | 19 +- .../ocpp/1.6/OCPP16ResponseService.ts | 233 ++++++----- .../ocpp/OCPPIncomingRequestService.ts | 26 +- .../ocpp/OCPPRequestService.ts | 97 +++-- .../ocpp/OCPPResponseService.ts | 23 +- src/types/ocpp/Requests.ts | 6 +- src/types/ocpp/Responses.ts | 2 + 10 files changed, 410 insertions(+), 397 deletions(-) diff --git a/src/charging-station/AutomaticTransactionGenerator.ts b/src/charging-station/AutomaticTransactionGenerator.ts index 23f78833..56e4feaa 100644 --- a/src/charging-station/AutomaticTransactionGenerator.ts +++ b/src/charging-station/AutomaticTransactionGenerator.ts @@ -281,7 +281,7 @@ export default class AutomaticTransactionGenerator { await this.chargingStation.ocppRequestService.requestHandler< AuthorizeRequest, AuthorizeResponse - >(RequestCommand.AUTHORIZE, { + >(this.chargingStation, RequestCommand.AUTHORIZE, { idTag, }); this.connectorsStatus.get(connectorId).authorizeRequests++; @@ -292,7 +292,7 @@ export default class AutomaticTransactionGenerator { startResponse = await this.chargingStation.ocppRequestService.requestHandler< StartTransactionRequest, StartTransactionResponse - >(RequestCommand.START_TRANSACTION, { + >(this.chargingStation, RequestCommand.START_TRANSACTION, { connectorId, idTag, }); @@ -308,7 +308,7 @@ export default class AutomaticTransactionGenerator { startResponse = await this.chargingStation.ocppRequestService.requestHandler< StartTransactionRequest, StartTransactionResponse - >(RequestCommand.START_TRANSACTION, { + >(this.chargingStation, RequestCommand.START_TRANSACTION, { connectorId, idTag, }); @@ -319,7 +319,7 @@ export default class AutomaticTransactionGenerator { startResponse = await this.chargingStation.ocppRequestService.requestHandler< StartTransactionRequest, StartTransactionResponse - >(RequestCommand.START_TRANSACTION, { connectorId }); + >(this.chargingStation, RequestCommand.START_TRANSACTION, { connectorId }); PerformanceStatistics.endMeasure(measureId, beginId); return startResponse; } @@ -348,7 +348,7 @@ export default class AutomaticTransactionGenerator { await this.chargingStation.ocppRequestService.requestHandler< MeterValuesRequest, MeterValuesResponse - >(RequestCommand.METER_VALUES, { + >(this.chargingStation, RequestCommand.METER_VALUES, { connectorId, transactionId, meterValue: transactionEndMeterValue, @@ -357,7 +357,7 @@ export default class AutomaticTransactionGenerator { stopResponse = await this.chargingStation.ocppRequestService.requestHandler< StopTransactionRequest, StopTransactionResponse - >(RequestCommand.STOP_TRANSACTION, { + >(this.chargingStation, RequestCommand.STOP_TRANSACTION, { transactionId, meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), idTag: this.chargingStation.getTransactionIdTag(transactionId), diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index d36700d6..cd84076e 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -452,6 +452,7 @@ export default class ChargingStation { // eslint-disable-next-line @typescript-eslint/no-misused-promises this.heartbeatSetInterval = setInterval(async (): Promise => { await this.ocppRequestService.requestHandler( + this, RequestCommand.HEARTBEAT ); }, this.getHeartbeatInterval()); @@ -524,6 +525,7 @@ export default class ChargingStation { interval ); await this.ocppRequestService.requestHandler( + this, RequestCommand.METER_VALUES, { connectorId, @@ -631,7 +633,7 @@ export default class ChargingStation { await this.ocppRequestService.requestHandler< StatusNotificationRequest, StatusNotificationResponse - >(RequestCommand.STATUS_NOTIFICATION, { + >(this, RequestCommand.STATUS_NOTIFICATION, { connectorId, status: ChargePointStatus.UNAVAILABLE, errorCode: ChargePointErrorCode.NO_ERROR, @@ -1160,10 +1162,9 @@ export default class ChargingStation { switch (this.getOcppVersion()) { case OCPPVersion.VERSION_16: this.ocppIncomingRequestService = - OCPP16IncomingRequestService.getInstance(this); + OCPP16IncomingRequestService.getInstance(); this.ocppRequestService = OCPP16RequestService.getInstance( - this, - OCPP16ResponseService.getInstance(this) + OCPP16ResponseService.getInstance() ); break; default: @@ -1489,6 +1490,7 @@ export default class ChargingStation { BootNotificationRequest, BootNotificationResponse >( + this, RequestCommand.BOOT_NOTIFICATION, { chargePointModel: this.bootNotificationRequest.chargePointModel, @@ -1594,6 +1596,7 @@ export default class ChargingStation { ); // Process the message await this.ocppIncomingRequestService.incomingRequestHandler( + this, messageId, commandName, commandPayload @@ -1684,6 +1687,7 @@ export default class ChargingStation { // Send error messageType === MessageType.CALL_MESSAGE && (await this.ocppRequestService.sendError( + this, messageId, error as OCPPError, commandName ?? requestCommandName ?? null @@ -1867,6 +1871,7 @@ export default class ChargingStation { BootNotificationRequest, BootNotificationResponse >( + this, RequestCommand.BOOT_NOTIFICATION, { chargePointModel: this.bootNotificationRequest.chargePointModel, @@ -1899,7 +1904,7 @@ export default class ChargingStation { await this.ocppRequestService.requestHandler< StatusNotificationRequest, StatusNotificationResponse - >(RequestCommand.STATUS_NOTIFICATION, { + >(this, RequestCommand.STATUS_NOTIFICATION, { connectorId, status: this.getConnectorStatus(connectorId).bootStatus, errorCode: ChargePointErrorCode.NO_ERROR, @@ -1915,7 +1920,7 @@ export default class ChargingStation { await this.ocppRequestService.requestHandler< StatusNotificationRequest, StatusNotificationResponse - >(RequestCommand.STATUS_NOTIFICATION, { + >(this, RequestCommand.STATUS_NOTIFICATION, { connectorId, status: this.getConnectorStatus(connectorId).bootStatus, errorCode: ChargePointErrorCode.NO_ERROR, @@ -1927,7 +1932,7 @@ export default class ChargingStation { await this.ocppRequestService.requestHandler< StatusNotificationRequest, StatusNotificationResponse - >(RequestCommand.STATUS_NOTIFICATION, { + >(this, RequestCommand.STATUS_NOTIFICATION, { connectorId, status: this.getConnectorStatus(connectorId).status, errorCode: ChargePointErrorCode.NO_ERROR, @@ -1937,7 +1942,7 @@ export default class ChargingStation { await this.ocppRequestService.requestHandler< StatusNotificationRequest, StatusNotificationResponse - >(RequestCommand.STATUS_NOTIFICATION, { + >(this, RequestCommand.STATUS_NOTIFICATION, { connectorId, status: ChargePointStatus.AVAILABLE, errorCode: ChargePointErrorCode.NO_ERROR, @@ -1989,6 +1994,7 @@ export default class ChargingStation { this.getEnergyActiveImportRegisterByTransactionId(transactionId) ); await this.ocppRequestService.requestHandler( + this, RequestCommand.METER_VALUES, { connectorId, @@ -2000,7 +2006,7 @@ export default class ChargingStation { await this.ocppRequestService.requestHandler< StopTransactionRequest, StopTransactionResponse - >(RequestCommand.STOP_TRANSACTION, { + >(this, RequestCommand.STOP_TRANSACTION, { transactionId, meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId), idTag: this.getTransactionIdTag(transactionId), diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 8dc9135f..45f3723c 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -84,11 +84,11 @@ const moduleName = 'OCPP16IncomingRequestService'; export default class OCPP16IncomingRequestService extends OCPPIncomingRequestService { private incomingRequestHandlers: Map; - public constructor(chargingStation: ChargingStation) { + public constructor() { if (new.target?.name === moduleName) { throw new TypeError(`Cannot construct ${new.target?.name} instances directly`); } - super(chargingStation); + super(); this.incomingRequestHandlers = new Map([ [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)], [OCPP16IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)], @@ -127,14 +127,15 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } public async incomingRequestHandler( + chargingStation: ChargingStation, messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: JsonType ): Promise { let response: JsonType; if ( - this.chargingStation.getOcppStrictCompliance() && - this.chargingStation.isInPendingState() && + chargingStation.getOcppStrictCompliance() && + chargingStation.isInPendingState() && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION) ) { @@ -149,16 +150,19 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer ); } if ( - this.chargingStation.isRegistered() || - (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState()) + chargingStation.isRegistered() || + (!chargingStation.getOcppStrictCompliance() && chargingStation.isInUnknownState()) ) { if (this.incomingRequestHandlers.has(commandName)) { try { // Call the method to build the response - response = await this.incomingRequestHandlers.get(commandName)(commandPayload); + response = await this.incomingRequestHandlers.get(commandName)( + chargingStation, + commandPayload + ); } catch (error) { // Log - logger.error(this.chargingStation.logPrefix() + ' Handle request error: %j', error); + logger.error(chargingStation.logPrefix() + ' Handle request error: %j', error); throw error; } } else { @@ -185,22 +189,28 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer ); } // Send the built response - await this.chargingStation.ocppRequestService.sendResponse(messageId, response, commandName); + await chargingStation.ocppRequestService.sendResponse( + chargingStation, + messageId, + response, + commandName + ); } // Simulate charging station restart - private handleRequestReset(commandPayload: ResetRequest): DefaultResponse { + private handleRequestReset( + chargingStation: ChargingStation, + commandPayload: ResetRequest + ): DefaultResponse { // eslint-disable-next-line @typescript-eslint/no-misused-promises setImmediate(async (): Promise => { - await this.chargingStation.reset( - (commandPayload.type + 'Reset') as OCPP16StopTransactionReason - ); + await chargingStation.reset((commandPayload.type + 'Reset') as OCPP16StopTransactionReason); }); logger.info( - `${this.chargingStation.logPrefix()} ${ + `${chargingStation.logPrefix()} ${ commandPayload.type } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds( - this.chargingStation.stationInfo.resetTime + chargingStation.stationInfo.resetTime )}` ); return Constants.OCPP_RESPONSE_ACCEPTED; @@ -211,44 +221,45 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestUnlockConnector( + chargingStation: ChargingStation, commandPayload: UnlockConnectorRequest ): Promise { const connectorId = commandPayload.connectorId; if (connectorId === 0) { logger.error( - this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString() + chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString() ); return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED; } - if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) { - const transactionId = this.chargingStation.getConnectorStatus(connectorId).transactionId; + if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted) { + const transactionId = chargingStation.getConnectorStatus(connectorId).transactionId; if ( - this.chargingStation.getBeginEndMeterValues() && - this.chargingStation.getOcppStrictCompliance() && - !this.chargingStation.getOutOfOrderEndMeterValues() + chargingStation.getBeginEndMeterValues() && + chargingStation.getOcppStrictCompliance() && + !chargingStation.getOutOfOrderEndMeterValues() ) { // FIXME: Implement OCPP version agnostic helpers const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue( - this.chargingStation, + chargingStation, connectorId, - this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) + chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) ); - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16MeterValuesRequest, OCPP16MeterValuesResponse - >(OCPP16RequestCommand.METER_VALUES, { + >(chargingStation, OCPP16RequestCommand.METER_VALUES, { connectorId, transactionId, meterValue: transactionEndMeterValue, }); } - const stopResponse = await this.chargingStation.ocppRequestService.requestHandler< + const stopResponse = await chargingStation.ocppRequestService.requestHandler< OCPP16StopTransactionRequest, OCPP16StopTransactionResponse - >(OCPP16RequestCommand.STOP_TRANSACTION, { + >(chargingStation, OCPP16RequestCommand.STOP_TRANSACTION, { transactionId, - meterStop: this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), - idTag: this.chargingStation.getTransactionIdTag(transactionId), + meterStop: chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), + idTag: chargingStation.getTransactionIdTag(transactionId), reason: OCPP16StopTransactionReason.UNLOCK_COMMAND, }); if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { @@ -256,25 +267,26 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } return Constants.OCPP_RESPONSE_UNLOCK_FAILED; } - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, status: OCPP16ChargePointStatus.AVAILABLE, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE; + chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE; return Constants.OCPP_RESPONSE_UNLOCKED; } private handleRequestGetConfiguration( + chargingStation: ChargingStation, commandPayload: GetConfigurationRequest ): GetConfigurationResponse { const configurationKey: OCPPConfigurationKey[] = []; const unknownKey: string[] = []; if (Utils.isEmptyArray(commandPayload.key)) { - for (const configuration of this.chargingStation.ocppConfiguration.configurationKey) { + for (const configuration of chargingStation.ocppConfiguration.configurationKey) { if (Utils.isUndefined(configuration.visible)) { configuration.visible = true; } @@ -289,7 +301,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } } else { for (const key of commandPayload.key) { - const keyFound = this.chargingStation.getConfigurationKey(key); + const keyFound = chargingStation.getConfigurationKey(key); if (keyFound) { if (Utils.isUndefined(keyFound.visible)) { keyFound.visible = true; @@ -314,12 +326,13 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private handleRequestChangeConfiguration( + chargingStation: ChargingStation, commandPayload: ChangeConfigurationRequest ): ChangeConfigurationResponse { // JSON request fields type sanity check if (!Utils.isString(commandPayload.key)) { logger.error( - `${this.chargingStation.logPrefix()} ${ + `${chargingStation.logPrefix()} ${ OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION } request key field is not a string:`, commandPayload @@ -327,13 +340,13 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } if (!Utils.isString(commandPayload.value)) { logger.error( - `${this.chargingStation.logPrefix()} ${ + `${chargingStation.logPrefix()} ${ OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION } request value field is not a string:`, commandPayload ); } - const keyToChange = this.chargingStation.getConfigurationKey(commandPayload.key, true); + const keyToChange = chargingStation.getConfigurationKey(commandPayload.key, true); if (!keyToChange) { return Constants.OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED; } else if (keyToChange && keyToChange.readonly) { @@ -341,33 +354,29 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } else if (keyToChange && !keyToChange.readonly) { let valueChanged = false; if (keyToChange.value !== commandPayload.value) { - this.chargingStation.setConfigurationKeyValue( - commandPayload.key, - commandPayload.value, - true - ); + chargingStation.setConfigurationKeyValue(commandPayload.key, commandPayload.value, true); valueChanged = true; } let triggerHeartbeatRestart = false; if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) { - this.chargingStation.setConfigurationKeyValue( + chargingStation.setConfigurationKeyValue( OCPP16StandardParametersKey.HeartbeatInterval, commandPayload.value ); triggerHeartbeatRestart = true; } if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) { - this.chargingStation.setConfigurationKeyValue( + chargingStation.setConfigurationKeyValue( OCPP16StandardParametersKey.HeartBeatInterval, commandPayload.value ); triggerHeartbeatRestart = true; } if (triggerHeartbeatRestart) { - this.chargingStation.restartHeartbeat(); + chargingStation.restartHeartbeat(); } if (keyToChange.key === OCPP16StandardParametersKey.WebSocketPingInterval && valueChanged) { - this.chargingStation.restartWebSocketPing(); + chargingStation.restartWebSocketPing(); } if (keyToChange.reboot) { return Constants.OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED; @@ -377,20 +386,21 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private handleRequestSetChargingProfile( + chargingStation: ChargingStation, commandPayload: SetChargingProfileRequest ): SetChargingProfileResponse { if ( !OCPP16ServiceUtils.checkFeatureProfile( - this.chargingStation, + chargingStation, OCPP16SupportedFeatureProfiles.SmartCharging, OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE ) ) { return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED; } - if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) { + if (!chargingStation.getConnectorStatus(commandPayload.connectorId)) { logger.error( - `${this.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 }` ); @@ -407,39 +417,40 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE && (commandPayload.connectorId === 0 || - !this.chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted) + !chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted) ) { return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED; } - this.chargingStation.setChargingProfile( + chargingStation.setChargingProfile( commandPayload.connectorId, commandPayload.csChargingProfiles ); logger.debug( - `${this.chargingStation.logPrefix()} Charging profile(s) set on connector id ${ + `${chargingStation.logPrefix()} Charging profile(s) set on connector id ${ commandPayload.connectorId }, dump their stack: %j`, - this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles + chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles ); return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED; } private handleRequestClearChargingProfile( + chargingStation: ChargingStation, commandPayload: ClearChargingProfileRequest ): ClearChargingProfileResponse { if ( !OCPP16ServiceUtils.checkFeatureProfile( - this.chargingStation, + chargingStation, OCPP16SupportedFeatureProfiles.SmartCharging, OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE ) ) { return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN; } - const connectorStatus = this.chargingStation.getConnectorStatus(commandPayload.connectorId); + const connectorStatus = chargingStation.getConnectorStatus(commandPayload.connectorId); if (!connectorStatus) { logger.error( - `${this.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 }` ); @@ -448,7 +459,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer if (commandPayload.connectorId && !Utils.isEmptyArray(connectorStatus.chargingProfiles)) { connectorStatus.chargingProfiles = []; logger.debug( - `${this.chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${ + `${chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${ commandPayload.connectorId }, dump their stack: %j`, connectorStatus.chargingProfiles @@ -457,11 +468,9 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } if (!commandPayload.connectorId) { let clearedCP = false; - for (const connectorId of this.chargingStation.connectors.keys()) { - if ( - !Utils.isEmptyArray(this.chargingStation.getConnectorStatus(connectorId).chargingProfiles) - ) { - this.chargingStation + for (const connectorId of chargingStation.connectors.keys()) { + if (!Utils.isEmptyArray(chargingStation.getConnectorStatus(connectorId).chargingProfiles)) { + chargingStation .getConnectorStatus(connectorId) .chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => { let clearCurrentCP = false; @@ -489,7 +498,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer if (clearCurrentCP) { connectorStatus.chargingProfiles[index] = {} as OCPP16ChargingProfile; logger.debug( - `${this.chargingStation.logPrefix()} Matching charging profile(s) cleared on connector id ${ + `${chargingStation.logPrefix()} Matching charging profile(s) cleared on connector id ${ commandPayload.connectorId }, dump their stack: %j`, connectorStatus.chargingProfiles @@ -507,12 +516,13 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestChangeAvailability( + chargingStation: ChargingStation, commandPayload: ChangeAvailabilityRequest ): Promise { const connectorId: number = commandPayload.connectorId; - if (!this.chargingStation.getConnectorStatus(connectorId)) { + if (!chargingStation.getConnectorStatus(connectorId)) { logger.error( - `${this.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 Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED; } @@ -522,85 +532,85 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer : OCPP16ChargePointStatus.UNAVAILABLE; if (connectorId === 0) { let response: ChangeAvailabilityResponse = Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; - for (const id of this.chargingStation.connectors.keys()) { - if (this.chargingStation.getConnectorStatus(id)?.transactionStarted) { + for (const id of chargingStation.connectors.keys()) { + if (chargingStation.getConnectorStatus(id)?.transactionStarted) { response = Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } - this.chargingStation.getConnectorStatus(id).availability = commandPayload.type; + chargingStation.getConnectorStatus(id).availability = commandPayload.type; if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId: id, status: chargePointStatus, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(id).status = chargePointStatus; + chargingStation.getConnectorStatus(id).status = chargePointStatus; } } return response; } else if ( connectorId > 0 && - (this.chargingStation.getConnectorStatus(0).availability === - OCPP16AvailabilityType.OPERATIVE || - (this.chargingStation.getConnectorStatus(0).availability === + (chargingStation.getConnectorStatus(0).availability === OCPP16AvailabilityType.OPERATIVE || + (chargingStation.getConnectorStatus(0).availability === OCPP16AvailabilityType.INOPERATIVE && commandPayload.type === OCPP16AvailabilityType.INOPERATIVE)) ) { - if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) { - this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type; + if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted) { + chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type; return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED; } - this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type; - await this.chargingStation.ocppRequestService.requestHandler< + chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type; + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, status: chargePointStatus, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(connectorId).status = chargePointStatus; + chargingStation.getConnectorStatus(connectorId).status = chargePointStatus; return Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED; } return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED; } private async handleRequestRemoteStartTransaction( + chargingStation: ChargingStation, commandPayload: RemoteStartTransactionRequest ): Promise { const transactionConnectorId = commandPayload.connectorId; - const connectorStatus = this.chargingStation.getConnectorStatus(transactionConnectorId); + const connectorStatus = chargingStation.getConnectorStatus(transactionConnectorId); if (transactionConnectorId) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId: transactionConnectorId, status: OCPP16ChargePointStatus.PREPARING, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); connectorStatus.status = OCPP16ChargePointStatus.PREPARING; - if (this.chargingStation.isChargingStationAvailable() && connectorStatus) { + if (chargingStation.isChargingStationAvailable() && connectorStatus) { // Check if authorized - if (this.chargingStation.getAuthorizeRemoteTxRequests()) { + if (chargingStation.getAuthorizeRemoteTxRequests()) { let authorized = false; if ( - this.chargingStation.getLocalAuthListEnabled() && - this.chargingStation.hasAuthorizedTags() && - this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag) + chargingStation.getLocalAuthListEnabled() && + chargingStation.hasAuthorizedTags() && + chargingStation.authorizedTags.find((value) => value === commandPayload.idTag) ) { connectorStatus.localAuthorizeIdTag = commandPayload.idTag; connectorStatus.idTagLocalAuthorized = true; authorized = true; - } else if (this.chargingStation.getMayAuthorizeAtRemoteStart()) { + } else if (chargingStation.getMayAuthorizeAtRemoteStart()) { connectorStatus.authorizeIdTag = commandPayload.idTag; const authorizeResponse: OCPP16AuthorizeResponse = - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16AuthorizeRequest, OCPP16AuthorizeResponse - >(OCPP16RequestCommand.AUTHORIZE, { + >(chargingStation, OCPP16RequestCommand.AUTHORIZE, { idTag: commandPayload.idTag, }); if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { @@ -608,13 +618,14 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } } else { logger.warn( - `${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled` + `${chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled` ); } if (authorized) { // Authorization successful, start transaction if ( this.setRemoteStartTransactionChargingProfile( + chargingStation, transactionConnectorId, commandPayload.chargingProfile ) @@ -622,19 +633,19 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer connectorStatus.transactionRemoteStarted = true; if ( ( - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StartTransactionRequest, OCPP16StartTransactionResponse - >(OCPP16RequestCommand.START_TRANSACTION, { + >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, { connectorId: transactionConnectorId, idTag: commandPayload.idTag, }) ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED ) { logger.debug( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + - this.chargingStation.stationInfo.chargingStationId + + chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + @@ -643,16 +654,19 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer return Constants.OCPP_RESPONSE_ACCEPTED; } return this.notifyRemoteStartTransactionRejected( + chargingStation, transactionConnectorId, commandPayload.idTag ); } return this.notifyRemoteStartTransactionRejected( + chargingStation, transactionConnectorId, commandPayload.idTag ); } return this.notifyRemoteStartTransactionRejected( + chargingStation, transactionConnectorId, commandPayload.idTag ); @@ -660,6 +674,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer // No authorization check required, start transaction if ( this.setRemoteStartTransactionChargingProfile( + chargingStation, transactionConnectorId, commandPayload.chargingProfile ) @@ -667,19 +682,19 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer connectorStatus.transactionRemoteStarted = true; if ( ( - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StartTransactionRequest, OCPP16StartTransactionResponse - >(OCPP16RequestCommand.START_TRANSACTION, { + >(chargingStation, OCPP16RequestCommand.START_TRANSACTION, { connectorId: transactionConnectorId, idTag: commandPayload.idTag, }) ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED ) { logger.debug( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + - this.chargingStation.stationInfo.chargingStationId + + chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + @@ -688,70 +703,77 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer return Constants.OCPP_RESPONSE_ACCEPTED; } return this.notifyRemoteStartTransactionRejected( + chargingStation, transactionConnectorId, commandPayload.idTag ); } return this.notifyRemoteStartTransactionRejected( + chargingStation, transactionConnectorId, commandPayload.idTag ); } return this.notifyRemoteStartTransactionRejected( + chargingStation, transactionConnectorId, commandPayload.idTag ); } - return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag); + return this.notifyRemoteStartTransactionRejected( + chargingStation, + transactionConnectorId, + commandPayload.idTag + ); } private async notifyRemoteStartTransactionRejected( + chargingStation: ChargingStation, connectorId: number, idTag: string ): Promise { if ( - this.chargingStation.getConnectorStatus(connectorId).status !== - OCPP16ChargePointStatus.AVAILABLE + chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE ) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, status: OCPP16ChargePointStatus.AVAILABLE, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(connectorId).status = - OCPP16ChargePointStatus.AVAILABLE; + chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE; } logger.warn( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + connectorId.toString() + ', idTag ' + idTag + ', availability ' + - this.chargingStation.getConnectorStatus(connectorId).availability + + chargingStation.getConnectorStatus(connectorId).availability + ', status ' + - this.chargingStation.getConnectorStatus(connectorId).status + chargingStation.getConnectorStatus(connectorId).status ); return Constants.OCPP_RESPONSE_REJECTED; } private setRemoteStartTransactionChargingProfile( + chargingStation: ChargingStation, connectorId: number, cp: OCPP16ChargingProfile ): boolean { if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) { - this.chargingStation.setChargingProfile(connectorId, cp); + chargingStation.setChargingProfile(connectorId, cp); logger.debug( - `${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}, dump their stack: %j`, - this.chargingStation.getConnectorStatus(connectorId).chargingProfiles + `${chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}, dump their stack: %j`, + chargingStation.getConnectorStatus(connectorId).chargingProfiles ); return true; } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) { logger.warn( - `${this.chargingStation.logPrefix()} Not allowed to set ${ + `${chargingStation.logPrefix()} Not allowed to set ${ cp.chargingProfilePurpose } charging profile(s) at remote start transaction` ); @@ -762,58 +784,57 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestRemoteStopTransaction( + chargingStation: ChargingStation, commandPayload: RemoteStopTransactionRequest ): Promise { const transactionId = commandPayload.transactionId; - for (const connectorId of this.chargingStation.connectors.keys()) { + for (const connectorId of chargingStation.connectors.keys()) { if ( connectorId > 0 && - this.chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId + chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId ) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, status: OCPP16ChargePointStatus.FINISHING, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(connectorId).status = - OCPP16ChargePointStatus.FINISHING; + chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.FINISHING; if ( - this.chargingStation.getBeginEndMeterValues() && - this.chargingStation.getOcppStrictCompliance() && - !this.chargingStation.getOutOfOrderEndMeterValues() + chargingStation.getBeginEndMeterValues() && + chargingStation.getOcppStrictCompliance() && + !chargingStation.getOutOfOrderEndMeterValues() ) { // FIXME: Implement OCPP version agnostic helpers const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue( - this.chargingStation, + chargingStation, connectorId, - this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) + chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) ); - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16MeterValuesRequest, OCPP16MeterValuesResponse - >(OCPP16RequestCommand.METER_VALUES, { + >(chargingStation, OCPP16RequestCommand.METER_VALUES, { connectorId, transactionId, meterValue: transactionEndMeterValue, }); } - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StopTransactionRequest, OCPP16StopTransactionResponse - >(OCPP16RequestCommand.STOP_TRANSACTION, { + >(chargingStation, OCPP16RequestCommand.STOP_TRANSACTION, { transactionId, - meterStop: - this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), - idTag: this.chargingStation.getTransactionIdTag(transactionId), + meterStop: chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId), + idTag: chargingStation.getTransactionIdTag(transactionId), }); return Constants.OCPP_RESPONSE_ACCEPTED; } } logger.info( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString() ); @@ -821,11 +842,12 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private async handleRequestGetDiagnostics( + chargingStation: ChargingStation, commandPayload: GetDiagnosticsRequest ): Promise { if ( !OCPP16ServiceUtils.checkFeatureProfile( - this.chargingStation, + chargingStation, OCPP16SupportedFeatureProfiles.FirmwareManagement, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS ) @@ -833,7 +855,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer return Constants.OCPP_RESPONSE_EMPTY; } logger.debug( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' ' + OCPP16IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', @@ -847,8 +869,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer .readdirSync(path.resolve(__dirname, '../../../../')) .filter((file) => file.endsWith('.log')) .map((file) => path.join('./', file)); - const diagnosticsArchive = - this.chargingStation.stationInfo.chargingStationId + '_logs.tar.gz'; + const diagnosticsArchive = chargingStation.stationInfo.chargingStationId + '_logs.tar.gz'; tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive)); ftpClient = new Client(); const accessResponse = await ftpClient.access({ @@ -862,14 +883,14 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer // eslint-disable-next-line @typescript-eslint/no-misused-promises ftpClient.trackProgress(async (info) => { logger.info( - `${this.chargingStation.logPrefix()} ${ + `${chargingStation.logPrefix()} ${ info.bytes / 1024 } bytes transferred from diagnostics archive ${info.name}` ); - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< DiagnosticsStatusNotificationRequest, DiagnosticsStatusNotificationResponse - >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.Uploading, }); }); @@ -878,10 +899,10 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer uri.pathname + diagnosticsArchive ); if (uploadResponse.code === 226) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< DiagnosticsStatusNotificationRequest, DiagnosticsStatusNotificationResponse - >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.Uploaded, }); if (ftpClient) { @@ -905,16 +926,17 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer OCPP16IncomingRequestCommand.GET_DIAGNOSTICS ); } catch (error) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< DiagnosticsStatusNotificationRequest, DiagnosticsStatusNotificationResponse - >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.UploadFailed, }); if (ftpClient) { ftpClient.close(); } return this.handleIncomingRequestError( + chargingStation, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, error as Error, { errorResponse: Constants.OCPP_RESPONSE_EMPTY } @@ -922,14 +944,14 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } } else { logger.error( - `${this.chargingStation.logPrefix()} Unsupported protocol ${ + `${chargingStation.logPrefix()} Unsupported protocol ${ uri.protocol } to transfer the diagnostic logs archive` ); - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< DiagnosticsStatusNotificationRequest, DiagnosticsStatusNotificationResponse - >(OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION, { status: OCPP16DiagnosticsStatus.UploadFailed, }); return Constants.OCPP_RESPONSE_EMPTY; @@ -937,11 +959,12 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } private handleRequestTriggerMessage( + chargingStation: ChargingStation, commandPayload: OCPP16TriggerMessageRequest ): OCPP16TriggerMessageResponse { if ( !OCPP16ServiceUtils.checkFeatureProfile( - this.chargingStation, + chargingStation, OCPP16SupportedFeatureProfiles.RemoteTrigger, OCPP16IncomingRequestCommand.TRIGGER_MESSAGE ) @@ -951,7 +974,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer // TODO: factor out the check on connector id if (commandPayload?.connectorId < 0) { logger.warn( - `${this.chargingStation.logPrefix()} ${ + `${chargingStation.logPrefix()} ${ OCPP16IncomingRequestCommand.TRIGGER_MESSAGE } incoming request received with invalid connectorId ${commandPayload.connectorId}` ); @@ -961,30 +984,27 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer switch (commandPayload.requestedMessage) { case MessageTrigger.BootNotification: setTimeout(() => { - this.chargingStation.ocppRequestService + chargingStation.ocppRequestService .requestHandler( + chargingStation, OCPP16RequestCommand.BOOT_NOTIFICATION, { - chargePointModel: - this.chargingStation.getBootNotificationRequest().chargePointModel, - chargePointVendor: - this.chargingStation.getBootNotificationRequest().chargePointVendor, + chargePointModel: chargingStation.getBootNotificationRequest().chargePointModel, + chargePointVendor: chargingStation.getBootNotificationRequest().chargePointVendor, chargeBoxSerialNumber: - this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber, - firmwareVersion: - this.chargingStation.getBootNotificationRequest().firmwareVersion, + chargingStation.getBootNotificationRequest().chargeBoxSerialNumber, + firmwareVersion: chargingStation.getBootNotificationRequest().firmwareVersion, chargePointSerialNumber: - this.chargingStation.getBootNotificationRequest().chargePointSerialNumber, - iccid: this.chargingStation.getBootNotificationRequest().iccid, - imsi: this.chargingStation.getBootNotificationRequest().imsi, - meterSerialNumber: - this.chargingStation.getBootNotificationRequest().meterSerialNumber, - meterType: this.chargingStation.getBootNotificationRequest().meterType, + chargingStation.getBootNotificationRequest().chargePointSerialNumber, + iccid: chargingStation.getBootNotificationRequest().iccid, + imsi: chargingStation.getBootNotificationRequest().imsi, + meterSerialNumber: chargingStation.getBootNotificationRequest().meterSerialNumber, + meterType: chargingStation.getBootNotificationRequest().meterType, }, { skipBufferingOnError: true, triggerMessage: true } ) .then((value) => { - this.chargingStation.bootNotificationResponse = value; + chargingStation.bootNotificationResponse = value; }) .catch(() => { /* This is intentional */ @@ -993,8 +1013,9 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; case MessageTrigger.Heartbeat: setTimeout(() => { - this.chargingStation.ocppRequestService + chargingStation.ocppRequestService .requestHandler( + chargingStation, OCPP16RequestCommand.HEARTBEAT, null, { @@ -1009,14 +1030,14 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer case MessageTrigger.StatusNotification: setTimeout(() => { if (commandPayload?.connectorId) { - this.chargingStation.ocppRequestService + chargingStation.ocppRequestService .requestHandler( + chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId: commandPayload.connectorId, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - status: this.chargingStation.getConnectorStatus(commandPayload.connectorId) - .status, + status: chargingStation.getConnectorStatus(commandPayload.connectorId).status, }, { triggerMessage: true, @@ -1026,17 +1047,18 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer /* This is intentional */ }); } else { - for (const connectorId of this.chargingStation.connectors.keys()) { - this.chargingStation.ocppRequestService + for (const connectorId of chargingStation.connectors.keys()) { + chargingStation.ocppRequestService .requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse >( + chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, - status: this.chargingStation.getConnectorStatus(connectorId).status, + status: chargingStation.getConnectorStatus(connectorId).status, }, { triggerMessage: true, @@ -1054,6 +1076,7 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer } } catch (error) { return this.handleIncomingRequestError( + chargingStation, OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, error as Error, { errorResponse: Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED } diff --git a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts index eb347480..3296dc94 100644 --- a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts @@ -16,22 +16,24 @@ import Utils from '../../../utils/Utils'; const moduleName = 'OCPP16RequestService'; export default class OCPP16RequestService extends OCPPRequestService { - public constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) { + public constructor(ocppResponseService: OCPPResponseService) { if (new.target?.name === moduleName) { throw new TypeError(`Cannot construct ${new.target?.name} instances directly`); } - super(chargingStation, ocppResponseService); + super(ocppResponseService); } public async requestHandler( + chargingStation: ChargingStation, commandName: OCPP16RequestCommand, commandParams?: JsonType, params?: RequestParams ): Promise { if (Object.values(OCPP16RequestCommand).includes(commandName)) { return (await this.sendMessage( + chargingStation, Utils.generateUUID(), - this.buildRequestPayload(commandName, commandParams), + this.buildRequestPayload(chargingStation, commandName, commandParams), commandName, params )) as unknown as Response; @@ -45,6 +47,7 @@ export default class OCPP16RequestService extends OCPPRequestService { } private buildRequestPayload( + chargingStation: ChargingStation, commandName: OCPP16RequestCommand, commandParams?: JsonType ): Request { @@ -105,13 +108,13 @@ export default class OCPP16RequestService extends OCPPRequestService { ...(!Utils.isUndefined(commandParams?.idTag) ? { idTag: commandParams?.idTag } : { idTag: Constants.DEFAULT_IDTAG }), - meterStart: this.chargingStation.getEnergyActiveImportRegisterByConnectorId( + meterStart: chargingStation.getEnergyActiveImportRegisterByConnectorId( commandParams?.connectorId as number ), timestamp: new Date().toISOString(), } as unknown as Request; case OCPP16RequestCommand.STOP_TRANSACTION: - connectorId = this.chargingStation.getConnectorIdByTransactionId( + connectorId = chargingStation.getConnectorIdByTransactionId( commandParams?.transactionId as number ); return { @@ -120,11 +123,11 @@ export default class OCPP16RequestService extends OCPPRequestService { meterStop: commandParams?.meterStop, timestamp: new Date().toISOString(), ...(commandParams?.reason && { reason: commandParams.reason }), - ...(this.chargingStation.getTransactionDataMeterValues() && { + ...(chargingStation.getTransactionDataMeterValues() && { transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues( - this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue, + chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue, OCPP16ServiceUtils.buildTransactionEndMeterValue( - this.chargingStation, + chargingStation, connectorId, commandParams?.meterStop as number ) diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 5a60af63..c4e7eef8 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -42,11 +42,11 @@ const moduleName = 'OCPP16ResponseService'; export default class OCPP16ResponseService extends OCPPResponseService { private responseHandlers: Map; - public constructor(chargingStation: ChargingStation) { + public constructor() { if (new.target?.name === moduleName) { throw new TypeError(`Cannot construct ${new.target?.name} instances directly`); } - super(chargingStation); + super(); this.responseHandlers = new Map([ [OCPP16RequestCommand.BOOT_NOTIFICATION, this.handleResponseBootNotification.bind(this)], [OCPP16RequestCommand.HEARTBEAT, this.handleResponseHeartbeat.bind(this)], @@ -59,22 +59,17 @@ export default class OCPP16ResponseService extends OCPPResponseService { } public async responseHandler( + chargingStation: ChargingStation, commandName: OCPP16RequestCommand, payload: JsonType, requestPayload: JsonType ): Promise { - if ( - this.chargingStation.isRegistered() || - commandName === OCPP16RequestCommand.BOOT_NOTIFICATION - ) { + if (chargingStation.isRegistered() || commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) { if (this.responseHandlers.has(commandName)) { try { - await this.responseHandlers.get(commandName)(payload, requestPayload); + await this.responseHandlers.get(commandName)(chargingStation, payload, requestPayload); } catch (error) { - logger.error( - this.chargingStation.logPrefix() + ' Handle request response error: %j', - error - ); + logger.error(chargingStation.logPrefix() + ' Handle request response error: %j', error); throw error; } } else { @@ -102,26 +97,29 @@ export default class OCPP16ResponseService extends OCPPResponseService { } } - private handleResponseBootNotification(payload: OCPP16BootNotificationResponse): void { + private handleResponseBootNotification( + chargingStation: ChargingStation, + payload: OCPP16BootNotificationResponse + ): void { if (payload.status === OCPP16RegistrationStatus.ACCEPTED) { - this.chargingStation.addConfigurationKey( + chargingStation.addConfigurationKey( OCPP16StandardParametersKey.HeartbeatInterval, payload.interval.toString(), {}, { overwrite: true, save: true } ); - this.chargingStation.addConfigurationKey( + chargingStation.addConfigurationKey( OCPP16StandardParametersKey.HeartBeatInterval, payload.interval.toString(), { visible: false }, { overwrite: true, save: true } ); - this.chargingStation.heartbeatSetInterval - ? this.chargingStation.restartHeartbeat() - : this.chargingStation.startHeartbeat(); + chargingStation.heartbeatSetInterval + ? chargingStation.restartHeartbeat() + : chargingStation.startHeartbeat(); } if (Object.values(OCPP16RegistrationStatus).includes(payload.status)) { - const logMsg = `${this.chargingStation.logPrefix()} Charging station in '${ + const logMsg = `${chargingStation.logPrefix()} Charging station in '${ payload.status }' state on the central server`; payload.status === OCPP16RegistrationStatus.REJECTED @@ -129,7 +127,7 @@ export default class OCPP16ResponseService extends OCPPResponseService { : logger.info(logMsg); } else { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Charging station boot notification response received: %j with undefined registration status', payload ); @@ -140,32 +138,32 @@ export default class OCPP16ResponseService extends OCPPResponseService { private handleResponseHeartbeat(): void {} private handleResponseAuthorize( + chargingStation: ChargingStation, payload: OCPP16AuthorizeResponse, requestPayload: OCPP16AuthorizeRequest ): void { let authorizeConnectorId: number; - for (const connectorId of this.chargingStation.connectors.keys()) { + for (const connectorId of chargingStation.connectors.keys()) { if ( connectorId > 0 && - this.chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === - requestPayload.idTag + chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag ) { authorizeConnectorId = connectorId; break; } } if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) { - this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true; + chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true; logger.debug( - `${this.chargingStation.logPrefix()} IdTag ${ + `${chargingStation.logPrefix()} IdTag ${ requestPayload.idTag } authorized on connector ${authorizeConnectorId}` ); } else { - this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false; - delete this.chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag; + chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false; + delete chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag; logger.debug( - `${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status '${ + `${chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status '${ payload.idTagInfo.status }' on connector ${authorizeConnectorId}` ); @@ -173,13 +171,14 @@ export default class OCPP16ResponseService extends OCPPResponseService { } private async handleResponseStartTransaction( + chargingStation: ChargingStation, payload: OCPP16StartTransactionResponse, requestPayload: OCPP16StartTransactionRequest ): Promise { const connectorId = requestPayload.connectorId; let transactionConnectorId: number; - for (const id of this.chargingStation.connectors.keys()) { + for (const id of chargingStation.connectors.keys()) { if (id > 0 && id === connectorId) { transactionConnectorId = id; break; @@ -187,105 +186,103 @@ export default class OCPP16ResponseService extends OCPPResponseService { } if (!transactionConnectorId) { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId.toString() ); return; } if ( - this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && - this.chargingStation.getAuthorizeRemoteTxRequests() && - this.chargingStation.getLocalAuthListEnabled() && - this.chargingStation.hasAuthorizedTags() && - !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized + chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && + chargingStation.getAuthorizeRemoteTxRequests() && + chargingStation.getLocalAuthListEnabled() && + chargingStation.hasAuthorizedTags() && + !chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized ) { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to start a transaction with a not local authorized idTag ' + - this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + + chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString() ); - await this.resetConnectorOnStartTransactionError(connectorId); + await this.resetConnectorOnStartTransactionError(chargingStation, connectorId); return; } if ( - this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && - this.chargingStation.getAuthorizeRemoteTxRequests() && - this.chargingStation.getMayAuthorizeAtRemoteStart() && - !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized && - !this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized + chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && + chargingStation.getAuthorizeRemoteTxRequests() && + chargingStation.getMayAuthorizeAtRemoteStart() && + !chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized && + !chargingStation.getConnectorStatus(connectorId).idTagAuthorized ) { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to start a transaction with a not authorized idTag ' + - this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + + chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString() ); - await this.resetConnectorOnStartTransactionError(connectorId); + await this.resetConnectorOnStartTransactionError(chargingStation, connectorId); return; } if ( - this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized && - this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag + chargingStation.getConnectorStatus(connectorId).idTagAuthorized && + chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag ) { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the authorize request one ' + - this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + + chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString() ); - await this.resetConnectorOnStartTransactionError(connectorId); + await this.resetConnectorOnStartTransactionError(chargingStation, connectorId); return; } if ( - this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized && - this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !== - requestPayload.idTag + chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized && + chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !== requestPayload.idTag ) { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the local authorized one ' + - this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + + chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString() ); - await this.resetConnectorOnStartTransactionError(connectorId); + await this.resetConnectorOnStartTransactionError(chargingStation, connectorId); return; } - if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) { + if (chargingStation.getConnectorStatus(connectorId)?.transactionStarted) { logger.debug( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to start a transaction on an already used connector ' + connectorId.toString() + ': %j', - this.chargingStation.getConnectorStatus(connectorId) + chargingStation.getConnectorStatus(connectorId) ); return; } if ( - this.chargingStation.getConnectorStatus(connectorId)?.status !== + chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.AVAILABLE && - this.chargingStation.getConnectorStatus(connectorId)?.status !== - OCPP16ChargePointStatus.PREPARING + chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.PREPARING ) { logger.error( - `${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${ - this.chargingStation.getConnectorStatus(connectorId)?.status + `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${ + chargingStation.getConnectorStatus(connectorId)?.status }` ); return; } if (!Number.isInteger(payload.transactionId)) { logger.warn( - `${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${ + `${chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${ payload.transactionId }, converting to integer` ); @@ -293,56 +290,54 @@ export default class OCPP16ResponseService extends OCPPResponseService { } if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { - this.chargingStation.getConnectorStatus(connectorId).transactionStarted = true; - this.chargingStation.getConnectorStatus(connectorId).transactionId = payload.transactionId; - this.chargingStation.getConnectorStatus(connectorId).transactionIdTag = requestPayload.idTag; - this.chargingStation.getConnectorStatus( + chargingStation.getConnectorStatus(connectorId).transactionStarted = true; + chargingStation.getConnectorStatus(connectorId).transactionId = payload.transactionId; + chargingStation.getConnectorStatus(connectorId).transactionIdTag = requestPayload.idTag; + chargingStation.getConnectorStatus( connectorId ).transactionEnergyActiveImportRegisterValue = 0; - this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue = + chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue = OCPP16ServiceUtils.buildTransactionBeginMeterValue( - this.chargingStation, + chargingStation, connectorId, requestPayload.meterStart ); - this.chargingStation.getBeginEndMeterValues() && - (await this.chargingStation.ocppRequestService.requestHandler< + chargingStation.getBeginEndMeterValues() && + (await chargingStation.ocppRequestService.requestHandler< OCPP16MeterValuesRequest, OCPP16MeterValuesResponse - >(OCPP16RequestCommand.METER_VALUES, { + >(chargingStation, OCPP16RequestCommand.METER_VALUES, { connectorId, transactionId: payload.transactionId, - meterValue: - this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue, + meterValue: chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue, })); - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, status: OCPP16ChargePointStatus.CHARGING, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(connectorId).status = - OCPP16ChargePointStatus.CHARGING; + chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.CHARGING; logger.info( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + - this.chargingStation.stationInfo.chargingStationId + + chargingStation.stationInfo.chargingStationId + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag ); - if (this.chargingStation.stationInfo.powerSharedByConnectors) { - this.chargingStation.stationInfo.powerDivider++; + if (chargingStation.stationInfo.powerSharedByConnectors) { + chargingStation.stationInfo.powerDivider++; } - const configuredMeterValueSampleInterval = this.chargingStation.getConfigurationKey( + const configuredMeterValueSampleInterval = chargingStation.getConfigurationKey( OCPP16StandardParametersKey.MeterValueSampleInterval ); - this.chargingStation.startMeterValues( + chargingStation.startMeterValues( connectorId, configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 @@ -350,7 +345,7 @@ export default class OCPP16ResponseService extends OCPPResponseService { ); } else { logger.warn( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + " REJECTED with status '" + @@ -358,102 +353,104 @@ export default class OCPP16ResponseService extends OCPPResponseService { "', idTag " + requestPayload.idTag ); - await this.resetConnectorOnStartTransactionError(connectorId); + await this.resetConnectorOnStartTransactionError(chargingStation, connectorId); } } - private async resetConnectorOnStartTransactionError(connectorId: number): Promise { - this.chargingStation.resetConnectorStatus(connectorId); + private async resetConnectorOnStartTransactionError( + chargingStation: ChargingStation, + connectorId: number + ): Promise { + chargingStation.resetConnectorStatus(connectorId); if ( - this.chargingStation.getConnectorStatus(connectorId).status !== - OCPP16ChargePointStatus.AVAILABLE + chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE ) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId, status: OCPP16ChargePointStatus.AVAILABLE, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(connectorId).status = - OCPP16ChargePointStatus.AVAILABLE; + chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE; } } private async handleResponseStopTransaction( + chargingStation: ChargingStation, payload: OCPP16StopTransactionResponse, requestPayload: OCPP16StopTransactionRequest ): Promise { - const transactionConnectorId = this.chargingStation.getConnectorIdByTransactionId( + const transactionConnectorId = chargingStation.getConnectorIdByTransactionId( requestPayload.transactionId ); if (!transactionConnectorId) { logger.error( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload.transactionId.toString() ); return; } if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) { - this.chargingStation.getBeginEndMeterValues() && - !this.chargingStation.getOcppStrictCompliance() && - this.chargingStation.getOutOfOrderEndMeterValues() && - (await this.chargingStation.ocppRequestService.requestHandler< + chargingStation.getBeginEndMeterValues() && + !chargingStation.getOcppStrictCompliance() && + chargingStation.getOutOfOrderEndMeterValues() && + (await chargingStation.ocppRequestService.requestHandler< OCPP16MeterValuesRequest, OCPP16MeterValuesResponse - >(OCPP16RequestCommand.METER_VALUES, { + >(chargingStation, OCPP16RequestCommand.METER_VALUES, { connectorId: transactionConnectorId, transactionId: requestPayload.transactionId, meterValue: OCPP16ServiceUtils.buildTransactionEndMeterValue( - this.chargingStation, + chargingStation, transactionConnectorId, requestPayload.meterStop ), })); if ( - !this.chargingStation.isChargingStationAvailable() || - !this.chargingStation.isConnectorAvailable(transactionConnectorId) + !chargingStation.isChargingStationAvailable() || + !chargingStation.isConnectorAvailable(transactionConnectorId) ) { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16StatusNotificationRequest, OCPP16StatusNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId: transactionConnectorId, status: OCPP16ChargePointStatus.UNAVAILABLE, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(transactionConnectorId).status = + chargingStation.getConnectorStatus(transactionConnectorId).status = OCPP16ChargePointStatus.UNAVAILABLE; } else { - await this.chargingStation.ocppRequestService.requestHandler< + await chargingStation.ocppRequestService.requestHandler< OCPP16BootNotificationRequest, OCPP16BootNotificationResponse - >(OCPP16RequestCommand.STATUS_NOTIFICATION, { + >(chargingStation, OCPP16RequestCommand.STATUS_NOTIFICATION, { connectorId: transactionConnectorId, status: OCPP16ChargePointStatus.AVAILABLE, errorCode: OCPP16ChargePointErrorCode.NO_ERROR, }); - this.chargingStation.getConnectorStatus(transactionConnectorId).status = + chargingStation.getConnectorStatus(transactionConnectorId).status = OCPP16ChargePointStatus.AVAILABLE; } - if (this.chargingStation.stationInfo.powerSharedByConnectors) { - this.chargingStation.stationInfo.powerDivider--; + if (chargingStation.stationInfo.powerSharedByConnectors) { + chargingStation.stationInfo.powerDivider--; } logger.info( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + - this.chargingStation.stationInfo.chargingStationId + + chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() ); - this.chargingStation.resetConnectorStatus(transactionConnectorId); + chargingStation.resetConnectorStatus(transactionConnectorId); } else { logger.warn( - this.chargingStation.logPrefix() + + chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + " REJECTED with status '" + diff --git a/src/charging-station/ocpp/OCPPIncomingRequestService.ts b/src/charging-station/ocpp/OCPPIncomingRequestService.ts index b5f607f5..bf517095 100644 --- a/src/charging-station/ocpp/OCPPIncomingRequestService.ts +++ b/src/charging-station/ocpp/OCPPIncomingRequestService.ts @@ -5,34 +5,27 @@ import { JsonType } from '../../types/JsonType'; import logger from '../../utils/Logger'; export default abstract class OCPPIncomingRequestService { - private static readonly instances: Map = new Map< - string, - OCPPIncomingRequestService - >(); + private static instance: OCPPIncomingRequestService | null = null; - protected chargingStation: ChargingStation; - - protected constructor(chargingStation: ChargingStation) { - this.chargingStation = chargingStation; + protected constructor() { + // This is intentional } - public static getInstance( - this: new (chargingStation: ChargingStation) => T, - chargingStation: ChargingStation - ): T { - if (!OCPPIncomingRequestService.instances.has(chargingStation.hashId)) { - OCPPIncomingRequestService.instances.set(chargingStation.hashId, new this(chargingStation)); + public static getInstance(this: new () => T): T { + if (!OCPPIncomingRequestService.instance) { + OCPPIncomingRequestService.instance = new this(); } - return OCPPIncomingRequestService.instances.get(chargingStation.hashId) as T; + return OCPPIncomingRequestService.instance as T; } protected handleIncomingRequestError( + chargingStation: ChargingStation, commandName: IncomingRequestCommand, error: Error, params: HandleErrorParams = { throwError: true } ): T { logger.error( - this.chargingStation.logPrefix() + ' Incoming request command %s error: %j', + chargingStation.logPrefix() + ' Incoming request command %s error: %j', commandName, error ); @@ -48,6 +41,7 @@ export default abstract class OCPPIncomingRequestService { } public abstract incomingRequestHandler( + chargingStation: ChargingStation, messageId: string, commandName: IncomingRequestCommand, commandPayload: JsonType diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index f8b6b227..1149cda5 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -8,7 +8,7 @@ import { } from '../../types/ocpp/Requests'; import { JsonObject, JsonType } from '../../types/JsonType'; -import type ChargingStation from '../ChargingStation'; +import ChargingStation from '../ChargingStation'; import Constants from '../../utils/Constants'; import { EmptyObject } from '../../types/EmptyObject'; import { ErrorType } from '../../types/ocpp/ErrorType'; @@ -21,19 +21,11 @@ import Utils from '../../utils/Utils'; import logger from '../../utils/Logger'; export default abstract class OCPPRequestService { - private static readonly instances: Map = new Map< - string, - OCPPRequestService - >(); + private static instance: OCPPRequestService | null = null; - protected readonly chargingStation: ChargingStation; private readonly ocppResponseService: OCPPResponseService; - protected constructor( - chargingStation: ChargingStation, - ocppResponseService: OCPPResponseService - ) { - this.chargingStation = chargingStation; + protected constructor(ocppResponseService: OCPPResponseService) { this.ocppResponseService = ocppResponseService; this.requestHandler.bind(this); this.sendResponse.bind(this); @@ -41,20 +33,17 @@ export default abstract class OCPPRequestService { } public static getInstance( - this: new (chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) => T, - chargingStation: ChargingStation, + this: new (ocppResponseService: OCPPResponseService) => T, ocppResponseService: OCPPResponseService ): T { - if (!OCPPRequestService.instances.has(chargingStation.hashId)) { - OCPPRequestService.instances.set( - chargingStation.hashId, - new this(chargingStation, ocppResponseService) - ); + if (!OCPPRequestService.instance) { + OCPPRequestService.instance = new this(ocppResponseService); } - return OCPPRequestService.instances.get(chargingStation.hashId) as T; + return OCPPRequestService.instance as T; } public async sendResponse( + chargingStation: ChargingStation, messageId: string, messagePayload: JsonType, commandName: IncomingRequestCommand @@ -62,17 +51,19 @@ export default abstract class OCPPRequestService { try { // Send response message return await this.internalSendMessage( + chargingStation, messageId, messagePayload, MessageType.CALL_RESULT_MESSAGE, commandName ); } catch (error) { - this.handleRequestError(commandName, error as Error); + this.handleRequestError(chargingStation, commandName, error as Error); } } public async sendError( + chargingStation: ChargingStation, messageId: string, ocppError: OCPPError, commandName: RequestCommand | IncomingRequestCommand @@ -80,17 +71,19 @@ export default abstract class OCPPRequestService { try { // Send error message return await this.internalSendMessage( + chargingStation, messageId, ocppError, MessageType.CALL_ERROR_MESSAGE, commandName ); } catch (error) { - this.handleRequestError(commandName, error as Error); + this.handleRequestError(chargingStation, commandName, error as Error); } } protected async sendMessage( + chargingStation: ChargingStation, messageId: string, messagePayload: JsonType, commandName: RequestCommand, @@ -101,6 +94,7 @@ export default abstract class OCPPRequestService { ): Promise { try { return await this.internalSendMessage( + chargingStation, messageId, messagePayload, MessageType.CALL_MESSAGE, @@ -108,11 +102,12 @@ export default abstract class OCPPRequestService { params ); } catch (error) { - this.handleRequestError(commandName, error as Error, { throwError: false }); + this.handleRequestError(chargingStation, commandName, error as Error, { throwError: false }); } } private async internalSendMessage( + chargingStation: ChargingStation, messageId: string, messagePayload: JsonType | OCPPError, messageType: MessageType, @@ -123,12 +118,10 @@ export default abstract class OCPPRequestService { } ): Promise { if ( - (this.chargingStation.isInUnknownState() && - commandName === RequestCommand.BOOT_NOTIFICATION) || - (!this.chargingStation.getOcppStrictCompliance() && - this.chargingStation.isInUnknownState()) || - this.chargingStation.isInAcceptedState() || - (this.chargingStation.isInPendingState() && + (chargingStation.isInUnknownState() && commandName === RequestCommand.BOOT_NOTIFICATION) || + (!chargingStation.getOcppStrictCompliance() && chargingStation.isInUnknownState()) || + chargingStation.isInAcceptedState() || + (chargingStation.isInPendingState() && (params.triggerMessage || messageType === MessageType.CALL_RESULT_MESSAGE)) ) { // eslint-disable-next-line @typescript-eslint/no-this-alias @@ -137,6 +130,7 @@ export default abstract class OCPPRequestService { return Utils.promiseWithTimeout( new Promise((resolve, reject) => { const messageToSend = this.buildMessageToSend( + chargingStation, messageId, messagePayload, messageType, @@ -144,27 +138,24 @@ export default abstract class OCPPRequestService { responseCallback, errorCallback ); - if (this.chargingStation.getEnableStatistics()) { - this.chargingStation.performanceStatistics.addRequestStatistic( - commandName, - messageType - ); + if (chargingStation.getEnableStatistics()) { + chargingStation.performanceStatistics.addRequestStatistic(commandName, messageType); } // Check if wsConnection opened - if (this.chargingStation.isWebSocketConnectionOpened()) { + if (chargingStation.isWebSocketConnectionOpened()) { // Yes: Send Message const beginId = PerformanceStatistics.beginMeasure(commandName); // FIXME: Handle sending error - this.chargingStation.wsConnection.send(messageToSend); + chargingStation.wsConnection.send(messageToSend); PerformanceStatistics.endMeasure(commandName, beginId); logger.debug( - `${this.chargingStation.logPrefix()} >> Command '${commandName}' sent ${this.getMessageTypeString( + `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${this.getMessageTypeString( messageType )} payload: ${messageToSend}` ); } else if (!params.skipBufferingOnError) { // Buffer it - this.chargingStation.bufferMessage(messageToSend); + chargingStation.bufferMessage(messageToSend); const ocppError = new OCPPError( ErrorType.GENERIC_ERROR, `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`, @@ -197,6 +188,7 @@ export default abstract class OCPPRequestService { /** * Function that will receive the request's response * + * @param chargingStation * @param payload * @param requestPayload */ @@ -204,8 +196,8 @@ export default abstract class OCPPRequestService { payload: JsonType, requestPayload: JsonType ): Promise { - if (self.chargingStation.getEnableStatistics()) { - self.chargingStation.performanceStatistics.addRequestStatistic( + if (chargingStation.getEnableStatistics()) { + chargingStation.performanceStatistics.addRequestStatistic( commandName, MessageType.CALL_RESULT_MESSAGE ); @@ -213,6 +205,7 @@ export default abstract class OCPPRequestService { // Handle the request's response try { await self.ocppResponseService.responseHandler( + chargingStation, commandName as RequestCommand, payload, requestPayload @@ -221,7 +214,7 @@ export default abstract class OCPPRequestService { } catch (error) { reject(error); } finally { - self.chargingStation.requests.delete(messageId); + chargingStation.requests.delete(messageId); } } @@ -232,19 +225,19 @@ export default abstract class OCPPRequestService { * @param requestStatistic */ function errorCallback(error: OCPPError, requestStatistic = true): void { - if (requestStatistic && self.chargingStation.getEnableStatistics()) { - self.chargingStation.performanceStatistics.addRequestStatistic( + if (requestStatistic && chargingStation.getEnableStatistics()) { + chargingStation.performanceStatistics.addRequestStatistic( commandName, MessageType.CALL_ERROR_MESSAGE ); } logger.error( - `${self.chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`, + `${chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`, error, commandName, messagePayload ); - self.chargingStation.requests.delete(messageId); + chargingStation.requests.delete(messageId); reject(error); } }), @@ -256,19 +249,19 @@ export default abstract class OCPPRequestService { (messagePayload as JsonObject)?.details ?? {} ), () => { - messageType === MessageType.CALL_MESSAGE && - this.chargingStation.requests.delete(messageId); + messageType === MessageType.CALL_MESSAGE && chargingStation.requests.delete(messageId); } ); } throw new OCPPError( ErrorType.SECURITY_ERROR, - `Cannot send command ${commandName} payload when the charging station is in ${this.chargingStation.getRegistrationStatus()} state on the central server`, + `Cannot send command ${commandName} payload when the charging station is in ${chargingStation.getRegistrationStatus()} state on the central server`, commandName ); } private buildMessageToSend( + chargingStation: ChargingStation, messageId: string, messagePayload: JsonType | OCPPError, messageType: MessageType, @@ -282,7 +275,7 @@ export default abstract class OCPPRequestService { // Request case MessageType.CALL_MESSAGE: // Build request - this.chargingStation.requests.set(messageId, [ + chargingStation.requests.set(messageId, [ responseCallback, errorCallback, commandName, @@ -327,15 +320,12 @@ export default abstract class OCPPRequestService { } private handleRequestError( + chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, error: Error, params: HandleErrorParams = { throwError: true } ): void { - logger.error( - this.chargingStation.logPrefix() + ' Request command %s error: %j', - commandName, - error - ); + logger.error(chargingStation.logPrefix() + ' Request command %s error: %j', commandName, error); if (params?.throwError) { throw error; } @@ -343,6 +333,7 @@ export default abstract class OCPPRequestService { // eslint-disable-next-line @typescript-eslint/no-unused-vars public abstract requestHandler( + chargingStation: ChargingStation, commandName: RequestCommand, commandParams?: JsonType, params?: RequestParams diff --git a/src/charging-station/ocpp/OCPPResponseService.ts b/src/charging-station/ocpp/OCPPResponseService.ts index e838bd9f..19088aab 100644 --- a/src/charging-station/ocpp/OCPPResponseService.ts +++ b/src/charging-station/ocpp/OCPPResponseService.ts @@ -3,28 +3,21 @@ import { JsonType } from '../../types/JsonType'; import { RequestCommand } from '../../types/ocpp/Requests'; export default abstract class OCPPResponseService { - private static readonly instances: Map = new Map< - string, - OCPPResponseService - >(); + private static instance: OCPPResponseService | null = null; - protected readonly chargingStation: ChargingStation; - - protected constructor(chargingStation: ChargingStation) { - this.chargingStation = chargingStation; + protected constructor() { + // This is intentional } - public static getInstance( - this: new (chargingStation: ChargingStation) => T, - chargingStation: ChargingStation - ): T { - if (!OCPPResponseService.instances.has(chargingStation.hashId)) { - OCPPResponseService.instances.set(chargingStation.hashId, new this(chargingStation)); + public static getInstance(this: new () => T): T { + if (!OCPPResponseService.instance) { + OCPPResponseService.instance = new this(); } - return OCPPResponseService.instances.get(chargingStation.hashId) as T; + return OCPPResponseService.instance as T; } public abstract responseHandler( + chargingStation: ChargingStation, commandName: RequestCommand, payload: JsonType, requestPayload: JsonType diff --git a/src/types/ocpp/Requests.ts b/src/types/ocpp/Requests.ts index 16a79c05..b0037ae0 100644 --- a/src/types/ocpp/Requests.ts +++ b/src/types/ocpp/Requests.ts @@ -7,6 +7,7 @@ import { OCPP16StatusNotificationRequest, } from './1.6/Requests'; +import ChargingStation from '../../charging-station/ChargingStation'; import { JsonType } from '../JsonType'; import { MessageType } from './MessageType'; import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus'; @@ -24,7 +25,10 @@ export type CachedRequest = [ JsonType ]; -export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise; +export type IncomingRequestHandler = ( + chargingStation: ChargingStation, + commandPayload: JsonType +) => JsonType | Promise; export type ResponseType = JsonType | OCPPError; diff --git a/src/types/ocpp/Responses.ts b/src/types/ocpp/Responses.ts index baefc637..a3c6672c 100644 --- a/src/types/ocpp/Responses.ts +++ b/src/types/ocpp/Responses.ts @@ -11,6 +11,7 @@ import { OCPP16UnlockStatus, } from './1.6/Responses'; +import ChargingStation from '../../charging-station/ChargingStation'; import { ErrorType } from './ErrorType'; import { JsonType } from '../JsonType'; import { MessageType } from './MessageType'; @@ -21,6 +22,7 @@ export type Response = [MessageType.CALL_RESULT_MESSAGE, string, JsonType]; export type ErrorResponse = [MessageType.CALL_ERROR_MESSAGE, string, ErrorType, string, JsonType]; export type ResponseHandler = ( + chargingStation: ChargingStation, payload: JsonType, requestPayload?: JsonType ) => void | Promise; -- 2.34.1