X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FChargingStation.ts;h=457369ff1ad029f30046e47432cb40c3546cc551;hb=0a48f2b2d735de604a1604fd0e191212b355602f;hp=8240e5b0521a1ec80ab093d9646997daed6bbc11;hpb=ad8537a7e3abb286a639164a9c5a25d48e33744a;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 8240e5b0..457369ff 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -5,9 +5,12 @@ import { AvailabilityType, BootNotificationRequest, CachedRequest, + HeartbeatRequest, IncomingRequest, IncomingRequestCommand, + MeterValuesRequest, RequestCommand, + StatusNotificationRequest, } from '../types/ocpp/Requests'; import { BootNotificationResponse, @@ -39,7 +42,11 @@ import { VendorDefaultParametersKey, } from '../types/ocpp/Configuration'; import { MeterValue, MeterValueMeasurand, MeterValuePhase } from '../types/ocpp/MeterValues'; -import { StopTransactionReason, StopTransactionResponse } from '../types/ocpp/Transaction'; +import { + StopTransactionReason, + StopTransactionRequest, + StopTransactionResponse, +} from '../types/ocpp/Transaction'; import { WSError, WebSocketCloseEventStatusCode } from '../types/WebSocket'; import WebSocket, { Data, OPEN, RawData } from 'ws'; @@ -236,23 +243,25 @@ export default class ChargingStation { } public getConnectorMaximumAvailablePower(connectorId: number): number { - let amperageLimitationPowerLimit: number; - if (this.getAmperageLimitation() < this.stationInfo.maximumAmperage) { - amperageLimitationPowerLimit = - this.getCurrentOutType() === CurrentType.AC + let connectorAmperageLimitationPowerLimit: number; + if ( + !Utils.isNullOrUndefined(this.getAmperageLimitation()) && + this.getAmperageLimitation() < this.stationInfo.maximumAmperage + ) { + connectorAmperageLimitationPowerLimit = + (this.getCurrentOutType() === CurrentType.AC ? ACElectricUtils.powerTotal( this.getNumberOfPhases(), this.getVoltageOut(), this.getAmperageLimitation() * this.getNumberOfConnectors() ) - : DCElectricUtils.power(this.getVoltageOut(), this.getAmperageLimitation()); + : DCElectricUtils.power(this.getVoltageOut(), this.getAmperageLimitation())) / + this.stationInfo.powerDivider; } - const connectorChargingProfilePowerLimit = this.getChargingProfilePowerLimit(connectorId); const connectorMaximumPower = ((this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower) / this.stationInfo.powerDivider; - const connectorAmperageLimitationPowerLimit = - amperageLimitationPowerLimit / this.stationInfo.powerDivider; + const connectorChargingProfilePowerLimit = this.getChargingProfilePowerLimit(connectorId); return Math.min( isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower, isNaN(connectorAmperageLimitationPowerLimit) @@ -360,7 +369,7 @@ export default class ChargingStation { } if ( measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && - !this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes( + !this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData)?.value.includes( measurand ) ) { @@ -391,7 +400,7 @@ export default class ChargingStation { phase && sampledValueTemplates[index]?.phase === phase && sampledValueTemplates[index]?.measurand === measurand && - this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes( + this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData)?.value.includes( measurand ) ) { @@ -400,7 +409,7 @@ export default class ChargingStation { !phase && !sampledValueTemplates[index].phase && sampledValueTemplates[index]?.measurand === measurand && - this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes( + this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData)?.value.includes( measurand ) ) { @@ -435,7 +444,7 @@ export default class ChargingStation { ) { // eslint-disable-next-line @typescript-eslint/no-misused-promises this.heartbeatSetInterval = setInterval(async (): Promise => { - await this.ocppRequestService.sendMessageHandler( + await this.ocppRequestService.sendMessageHandler( RequestCommand.HEARTBEAT ); }, this.getHeartbeatInterval()); @@ -507,7 +516,7 @@ export default class ChargingStation { this.getConnectorStatus(connectorId).transactionId, interval ); - await this.ocppRequestService.sendMessageHandler( + await this.ocppRequestService.sendMessageHandler( RequestCommand.METER_VALUES, { connectorId, @@ -612,14 +621,14 @@ export default class ChargingStation { await this.stopMessageSequence(reason); for (const connectorId of this.connectors.keys()) { if (connectorId > 0) { - await this.ocppRequestService.sendMessageHandler( - RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - status: ChargePointStatus.UNAVAILABLE, - errorCode: ChargePointErrorCode.NO_ERROR, - } - ); + await this.ocppRequestService.sendMessageHandler< + StatusNotificationRequest, + StatusNotificationResponse + >(RequestCommand.STATUS_NOTIFICATION, { + connectorId, + status: ChargePointStatus.UNAVAILABLE, + errorCode: ChargePointErrorCode.NO_ERROR, + }); this.getConnectorStatus(connectorId).status = ChargePointStatus.UNAVAILABLE; } } @@ -731,7 +740,7 @@ export default class ChargingStation { timestamp >= chargingProfile.chargingSchedule?.startSchedule.getTime() && timestamp < chargingProfile.chargingSchedule?.startSchedule.getTime() + - chargingProfile.chargingSchedule.duration && + chargingProfile.chargingSchedule.duration * 1000 && chargingProfile?.stackLevel === Math.max(...chargingProfiles.map((cp) => cp?.stackLevel)) ); if (!Utils.isEmptyArray(chargingProfiles)) { @@ -742,12 +751,14 @@ export default class ChargingStation { (chargingSchedulePeriod, index) => { timestamp >= chargingProfile.chargingSchedule.startSchedule.getTime() + - chargingSchedulePeriod.startPeriod && - chargingProfile.chargingSchedule.chargingSchedulePeriod[index + 1] && - timestamp < - chargingProfile.chargingSchedule.startSchedule.getTime() + - chargingProfile.chargingSchedule.chargingSchedulePeriod[index + 1] - ?.startPeriod; + chargingSchedulePeriod.startPeriod * 1000 && + ((chargingProfile.chargingSchedule.chargingSchedulePeriod[index + 1] && + timestamp < + chargingProfile.chargingSchedule.startSchedule.getTime() + + chargingProfile.chargingSchedule.chargingSchedulePeriod[index + 1] + ?.startPeriod * + 1000) || + !chargingProfile.chargingSchedule.chargingSchedulePeriod[index + 1]); } ); if (!Utils.isEmptyArray(chargingSchedulePeriods)) { @@ -783,7 +794,9 @@ export default class ChargingStation { this.stationInfo.powerDivider; if (limit > connectorMaximumPower) { logger.error( - `${this.logPrefix()} Charging profile limit is greater than connector id ${connectorId} maximum, dump their stack: %j`, + `${this.logPrefix()} Charging profile id ${ + matchingChargingProfile.chargingProfileId + } limit is greater than connector id ${connectorId} maximum, dump charging profiles' stack: %j`, this.getConnectorStatus(connectorId).chargingProfiles ); limit = connectorMaximumPower; @@ -824,6 +837,12 @@ export default class ChargingStation { this.stopMeterValues(connectorId); } + public hasFeatureProfile(featureProfile: SupportedFeatureProfiles) { + return this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)?.value.includes( + featureProfile + ); + } + public bufferMessage(message: string): void { this.messageBuffer.add(message); } @@ -907,6 +926,8 @@ export default class ChargingStation { (stationInfo.chargePointSerialNumber = existingStationInfo.chargePointSerialNumber); existingStationInfo?.chargeBoxSerialNumber && (stationInfo.chargeBoxSerialNumber = existingStationInfo.chargeBoxSerialNumber); + existingStationInfo?.meterSerialNumber && + (stationInfo.meterSerialNumber = existingStationInfo.meterSerialNumber); } else { const serialNumberSuffix = params?.randomSerialNumber ? this.getRandomSerialNumberSuffix({ upperCase: params.randomSerialNumberUpperCase }) @@ -917,6 +938,9 @@ export default class ChargingStation { stationInfo.chargeBoxSerialNumber = stationInfo?.chargeBoxSerialNumberPrefix && stationInfo.chargeBoxSerialNumberPrefix + serialNumberSuffix; + stationInfo.meterSerialNumber = + stationInfo?.meterSerialNumberPrefix && + stationInfo.meterSerialNumberPrefix + serialNumberSuffix; } } @@ -1040,8 +1064,8 @@ export default class ChargingStation { }), ...(!Utils.isUndefined(stationInfo.iccid) && { iccid: stationInfo.iccid }), ...(!Utils.isUndefined(stationInfo.imsi) && { imsi: stationInfo.imsi }), - ...(!Utils.isUndefined(stationInfo.meterSerialNumber) && { - meterSerialNumber: stationInfo.meterSerialNumber, + ...(!Utils.isUndefined(stationInfo.meterSerialNumberPrefix) && { + meterSerialNumber: stationInfo.meterSerialNumberPrefix, }), ...(!Utils.isUndefined(stationInfo.meterType) && { meterType: stationInfo.meterType, @@ -1217,7 +1241,7 @@ export default class ChargingStation { if (!this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)) { this.addConfigurationKey( StandardParametersKey.SupportedFeatureProfiles, - `${SupportedFeatureProfiles.Core},${SupportedFeatureProfiles.Local_Auth_List_Management},${SupportedFeatureProfiles.Smart_Charging}` + `${SupportedFeatureProfiles.Core},${SupportedFeatureProfiles.FirmwareManagement},${SupportedFeatureProfiles.LocalAuthListManagement},${SupportedFeatureProfiles.SmartCharging},${SupportedFeatureProfiles.RemoteTrigger}` ); } this.addConfigurationKey( @@ -1257,8 +1281,8 @@ export default class ChargingStation { } if ( !this.getConfigurationKey(StandardParametersKey.LocalAuthListEnabled) && - this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles).value.includes( - SupportedFeatureProfiles.Local_Auth_List_Management + this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)?.value.includes( + SupportedFeatureProfiles.LocalAuthListManagement ) ) { this.addConfigurationKey(StandardParametersKey.LocalAuthListEnabled, 'false'); @@ -1373,22 +1397,24 @@ export default class ChargingStation { // Send BootNotification let registrationRetryCount = 0; do { - this.bootNotificationResponse = - await this.ocppRequestService.sendMessageHandler( - RequestCommand.BOOT_NOTIFICATION, - { - chargePointModel: this.bootNotificationRequest.chargePointModel, - chargePointVendor: this.bootNotificationRequest.chargePointVendor, - chargeBoxSerialNumber: this.bootNotificationRequest.chargeBoxSerialNumber, - firmwareVersion: this.bootNotificationRequest.firmwareVersion, - chargePointSerialNumber: this.bootNotificationRequest.chargePointSerialNumber, - iccid: this.bootNotificationRequest.iccid, - imsi: this.bootNotificationRequest.imsi, - meterSerialNumber: this.bootNotificationRequest.meterSerialNumber, - meterType: this.bootNotificationRequest.meterType, - }, - { skipBufferingOnError: true } - ); + this.bootNotificationResponse = await this.ocppRequestService.sendMessageHandler< + BootNotificationRequest, + BootNotificationResponse + >( + RequestCommand.BOOT_NOTIFICATION, + { + chargePointModel: this.bootNotificationRequest.chargePointModel, + chargePointVendor: this.bootNotificationRequest.chargePointVendor, + chargeBoxSerialNumber: this.bootNotificationRequest.chargeBoxSerialNumber, + firmwareVersion: this.bootNotificationRequest.firmwareVersion, + chargePointSerialNumber: this.bootNotificationRequest.chargePointSerialNumber, + iccid: this.bootNotificationRequest.iccid, + imsi: this.bootNotificationRequest.imsi, + meterSerialNumber: this.bootNotificationRequest.meterSerialNumber, + meterType: this.bootNotificationRequest.meterType, + }, + { skipBufferingOnError: true } + ); if (!this.isInAcceptedState()) { this.getRegistrationMaxRetries() !== -1 && registrationRetryCount++; await Utils.sleep( @@ -1718,7 +1744,10 @@ export default class ChargingStation { private async startMessageSequence(): Promise { if (this.stationInfo.autoRegister) { - await this.ocppRequestService.sendMessageHandler( + await this.ocppRequestService.sendMessageHandler< + BootNotificationRequest, + BootNotificationResponse + >( RequestCommand.BOOT_NOTIFICATION, { chargePointModel: this.bootNotificationRequest.chargePointModel, @@ -1748,14 +1777,14 @@ export default class ChargingStation { this.getConnectorStatus(connectorId)?.bootStatus ) { // Send status in template at startup - await this.ocppRequestService.sendMessageHandler( - RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - status: this.getConnectorStatus(connectorId).bootStatus, - errorCode: ChargePointErrorCode.NO_ERROR, - } - ); + await this.ocppRequestService.sendMessageHandler< + StatusNotificationRequest, + StatusNotificationResponse + >(RequestCommand.STATUS_NOTIFICATION, { + connectorId, + status: this.getConnectorStatus(connectorId).bootStatus, + errorCode: ChargePointErrorCode.NO_ERROR, + }); this.getConnectorStatus(connectorId).status = this.getConnectorStatus(connectorId).bootStatus; } else if ( @@ -1764,36 +1793,36 @@ export default class ChargingStation { this.getConnectorStatus(connectorId)?.bootStatus ) { // Send status in template after reset - await this.ocppRequestService.sendMessageHandler( - RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - status: this.getConnectorStatus(connectorId).bootStatus, - errorCode: ChargePointErrorCode.NO_ERROR, - } - ); + await this.ocppRequestService.sendMessageHandler< + StatusNotificationRequest, + StatusNotificationResponse + >(RequestCommand.STATUS_NOTIFICATION, { + connectorId, + status: this.getConnectorStatus(connectorId).bootStatus, + errorCode: ChargePointErrorCode.NO_ERROR, + }); this.getConnectorStatus(connectorId).status = this.getConnectorStatus(connectorId).bootStatus; } else if (!this.stopped && this.getConnectorStatus(connectorId)?.status) { // Send previous status at template reload - await this.ocppRequestService.sendMessageHandler( - RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - status: this.getConnectorStatus(connectorId).status, - errorCode: ChargePointErrorCode.NO_ERROR, - } - ); + await this.ocppRequestService.sendMessageHandler< + StatusNotificationRequest, + StatusNotificationResponse + >(RequestCommand.STATUS_NOTIFICATION, { + connectorId, + status: this.getConnectorStatus(connectorId).status, + errorCode: ChargePointErrorCode.NO_ERROR, + }); } else { // Send default status - await this.ocppRequestService.sendMessageHandler( - RequestCommand.STATUS_NOTIFICATION, - { - connectorId, - status: ChargePointStatus.AVAILABLE, - errorCode: ChargePointErrorCode.NO_ERROR, - } - ); + await this.ocppRequestService.sendMessageHandler< + StatusNotificationRequest, + StatusNotificationResponse + >(RequestCommand.STATUS_NOTIFICATION, { + connectorId, + status: ChargePointStatus.AVAILABLE, + errorCode: ChargePointErrorCode.NO_ERROR, + }); this.getConnectorStatus(connectorId).status = ChargePointStatus.AVAILABLE; } } @@ -1840,24 +1869,24 @@ export default class ChargingStation { connectorId, this.getEnergyActiveImportRegisterByTransactionId(transactionId) ); - await this.ocppRequestService.sendMessageHandler( - RequestCommand.METER_VALUES, - { - connectorId, - transactionId, - meterValue: transactionEndMeterValue, - } - ); - } - await this.ocppRequestService.sendMessageHandler( - RequestCommand.STOP_TRANSACTION, - { + await this.ocppRequestService.sendMessageHandler< + MeterValuesRequest, + MeterValuesResponse + >(RequestCommand.METER_VALUES, { + connectorId, transactionId, - meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId), - idTag: this.getTransactionIdTag(transactionId), - reason, - } - ); + meterValue: transactionEndMeterValue, + }); + } + await this.ocppRequestService.sendMessageHandler< + StopTransactionRequest, + StopTransactionResponse + >(RequestCommand.STOP_TRANSACTION, { + transactionId, + meterStop: this.getEnergyActiveImportRegisterByTransactionId(transactionId), + idTag: this.getTransactionIdTag(transactionId), + reason, + }); } } }