: defaultVoltageOut;
}
- public getMaximumConfiguredPower(): number | undefined {
- let maximumConfiguredPower =
- (this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower;
+ public getConnectorMaximumAvailablePower(connectorId: number): number {
+ let amperageLimitationPowerLimit: number;
if (this.getAmperageLimitation() < this.stationInfo.maximumAmperage) {
- maximumConfiguredPower =
+ amperageLimitationPowerLimit =
this.getCurrentOutType() === CurrentType.AC
? ACElectricUtils.powerTotal(
this.getNumberOfPhases(),
)
: DCElectricUtils.power(this.getVoltageOut(), this.getAmperageLimitation());
}
- return maximumConfiguredPower;
+ const connectorChargingProfilePowerLimit = this.getChargingProfilePowerLimit(connectorId);
+ const connectorMaximumPower =
+ ((this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower) /
+ this.stationInfo.powerDivider;
+ const connectorAmperageLimitationPowerLimit =
+ amperageLimitationPowerLimit / this.stationInfo.powerDivider;
+ return Math.min(
+ isNaN(connectorMaximumPower) ? Infinity : connectorMaximumPower,
+ isNaN(connectorAmperageLimitationPowerLimit)
+ ? Infinity
+ : connectorAmperageLimitationPowerLimit,
+ isNaN(connectorChargingProfilePowerLimit) ? Infinity : connectorChargingProfilePowerLimit
+ );
}
public getTransactionIdTag(transactionId: number): string | undefined {
}
}
- public getChargingProfileLimit(
- connectorId: number
- ): { limit: number; unit: ChargingRateUnitType } | undefined {
+ public getChargingProfilePowerLimit(connectorId: number): number | undefined {
const timestamp = new Date().getTime();
let matchingChargingProfile: ChargingProfile;
let chargingSchedulePeriods: ChargingSchedulePeriod[] = [];
- if (!Utils.isEmptyArray(this.getConnectorStatus(connectorId).chargingProfiles)) {
+ if (!Utils.isEmptyArray(this.getConnectorStatus(connectorId)?.chargingProfiles)) {
const chargingProfiles: ChargingProfile[] = this.getConnectorStatus(
connectorId
).chargingProfiles.filter(
}
}
}
-
- return (
- !Utils.isEmptyArray(chargingSchedulePeriods) && {
- limit: chargingSchedulePeriods[0].limit,
- unit: matchingChargingProfile.chargingSchedule.chargingRateUnit,
+ let limit: number;
+ if (!Utils.isEmptyArray(chargingSchedulePeriods)) {
+ switch (this.getCurrentOutType()) {
+ case CurrentType.AC:
+ limit =
+ matchingChargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
+ ? chargingSchedulePeriods[0].limit
+ : ACElectricUtils.powerTotal(
+ this.getNumberOfPhases(),
+ this.getVoltageOut(),
+ chargingSchedulePeriods[0].limit
+ );
+ break;
+ case CurrentType.DC:
+ limit =
+ matchingChargingProfile.chargingSchedule.chargingRateUnit === ChargingRateUnitType.WATT
+ ? chargingSchedulePeriods[0].limit
+ : DCElectricUtils.power(this.getVoltageOut(), chargingSchedulePeriods[0].limit);
}
- );
+ }
+ const connectorMaximumPower =
+ ((this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower) /
+ 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.getConnectorStatus(connectorId).chargingProfiles
+ );
+ limit = connectorMaximumPower;
+ }
+ return limit;
}
public setChargingProfile(connectorId: number, cp: ChargingProfile): void {
}
private getMaximumAmperage(): number | undefined {
+ const maximumPower = (this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower;
switch (this.getCurrentOutType()) {
case CurrentType.AC:
return ACElectricUtils.amperagePerPhaseFromPower(
this.getNumberOfPhases(),
- ((this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower) /
- this.getNumberOfConnectors(),
+ maximumPower / this.getNumberOfConnectors(),
this.getVoltageOut()
);
case CurrentType.DC:
- return DCElectricUtils.amperage(this.stationInfo.maximumPower, this.getVoltageOut());
+ return DCElectricUtils.amperage(maximumPower, this.getVoltageOut());
}
}
commandPayload.csChargingProfiles
);
logger.debug(
- `${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`,
+ `${this.chargingStation.logPrefix()} Charging profile(s) set on connector id ${
+ commandPayload.connectorId
+ }, dump their stack: %j`,
this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
);
return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
if (commandPayload.connectorId && !Utils.isEmptyArray(connectorStatus.chargingProfiles)) {
connectorStatus.chargingProfiles = [];
logger.debug(
- `${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`,
+ `${this.chargingStation.logPrefix()} Charging profile(s) cleared on connector id ${
+ commandPayload.connectorId
+ }, dump their stack: %j`,
connectorStatus.chargingProfiles
);
return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
if (clearCurrentCP) {
connectorStatus.chargingProfiles[index] = {} as OCPP16ChargingProfile;
logger.debug(
- `${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`,
+ `${this.chargingStation.logPrefix()} Matching charging profile(s) cleared on connector id ${
+ commandPayload.connectorId
+ }, dump their stack: %j`,
connectorStatus.chargingProfiles
);
clearedCP = true;
if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
this.chargingStation.setChargingProfile(connectorId, cp);
logger.debug(
- `${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`,
+ `${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction on connector id ${connectorId}, dump their stack: %j`,
this.chargingStation.getConnectorStatus(connectorId).chargingProfiles
);
return true;
} measurand value`;
const powerMeasurandValues = {} as MeasurandValues;
const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
- const maximumPower = Math.round(
- chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider
+ const connectorMaximumPower = Math.round(
+ chargingStation.getConnectorMaximumAvailablePower(connectorId)
);
- const maximumPowerPerPhase = Math.round(
- chargingStation.getMaximumConfiguredPower() /
- chargingStation.stationInfo.powerDivider /
+ const connectorMaximumPowerPerPhase = Math.round(
+ chargingStation.getConnectorMaximumAvailablePower(connectorId) /
chargingStation.getNumberOfPhases()
);
switch (chargingStation.getCurrentOutType()) {
powerMeasurandValues.L1 =
phase1FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
powerMeasurandValues.L2 =
phase2FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
powerMeasurandValues.L3 =
phase3FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
} else {
powerMeasurandValues.L1 = powerSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
powerSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maximumPower / unitDivider);
+ : Utils.getRandomFloatRounded(connectorMaximumPower / unitDivider);
powerMeasurandValues.L2 = 0;
powerMeasurandValues.L3 = 0;
}
powerSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maximumPower / unitDivider);
+ : Utils.getRandomFloatRounded(connectorMaximumPower / unitDivider);
break;
default:
logger.error(errMsg);
)
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
- const maximumPowerRounded = Utils.roundTo(maximumPower / unitDivider, 2);
+ const connectorMaximumPowerRounded = Utils.roundTo(connectorMaximumPower / unitDivider, 2);
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
- maximumPowerRounded ||
+ connectorMaximumPowerRounded ||
debug
) {
logger.error(
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
meterValue.sampledValue[sampledValuesIndex].value
- }/${maximumPowerRounded}`
+ }/${connectorMaximumPowerRounded}`
);
}
for (
)
);
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
- const maximumPowerPerPhaseRounded = Utils.roundTo(maximumPowerPerPhase / unitDivider, 2);
+ const connectorMaximumPowerPerPhaseRounded = Utils.roundTo(
+ connectorMaximumPowerPerPhase / unitDivider,
+ 2
+ );
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
- maximumPowerPerPhaseRounded ||
+ connectorMaximumPowerPerPhaseRounded ||
debug
) {
logger.error(
meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
meterValue.sampledValue[sampledValuesPerPhaseIndex].value
- }/${maximumPowerPerPhaseRounded}`
+ }/${connectorMaximumPowerPerPhaseRounded}`
);
}
}
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
} measurand value`;
const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
- let maximumAmperage: number;
+ let connectorMaximumAmperage: number;
switch (chargingStation.getCurrentOutType()) {
case CurrentType.AC:
- maximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
+ connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
chargingStation.getNumberOfPhases(),
- chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider,
+ chargingStation.getConnectorMaximumAvailablePower(connectorId),
chargingStation.getVoltageOut()
);
if (chargingStation.getNumberOfPhases() === 3) {
currentMeasurandValues.L1 =
phase1FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(maximumAmperage);
+ Utils.getRandomFloatRounded(connectorMaximumAmperage);
currentMeasurandValues.L2 =
phase2FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(maximumAmperage);
+ Utils.getRandomFloatRounded(connectorMaximumAmperage);
currentMeasurandValues.L3 =
phase3FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(maximumAmperage);
+ Utils.getRandomFloatRounded(connectorMaximumAmperage);
} else {
currentMeasurandValues.L1 = currentSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
currentSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maximumAmperage);
+ : Utils.getRandomFloatRounded(connectorMaximumAmperage);
currentMeasurandValues.L2 = 0;
currentMeasurandValues.L3 = 0;
}
);
break;
case CurrentType.DC:
- maximumAmperage = DCElectricUtils.amperage(
- chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider,
+ connectorMaximumAmperage = DCElectricUtils.amperage(
+ chargingStation.getConnectorMaximumAvailablePower(connectorId),
chargingStation.getVoltageOut()
);
currentMeasurandValues.allPhases = currentSampledValueTemplate.value
currentSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maximumAmperage);
+ : Utils.getRandomFloatRounded(connectorMaximumAmperage);
break;
default:
logger.error(errMsg);
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
if (
- Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maximumAmperage ||
+ Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
+ connectorMaximumAmperage ||
debug
) {
logger.error(
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
meterValue.sampledValue[sampledValuesIndex].value
- }/${maximumAmperage}`
+ }/${connectorMaximumAmperage}`
);
}
for (
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
- maximumAmperage ||
+ connectorMaximumAmperage ||
debug
) {
logger.error(
meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
meterValue.sampledValue[sampledValuesPerPhaseIndex].value
- }/${maximumAmperage}`
+ }/${connectorMaximumAmperage}`
);
}
}
);
const unitDivider =
energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
- const maximumEnergyRounded = Utils.roundTo(
- ((chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider) *
- interval) /
- (3600 * 1000),
+ const connectorMaximumEnergyRounded = Utils.roundTo(
+ (chargingStation.getConnectorMaximumAvailablePower(connectorId) * interval) / (3600 * 1000),
2
);
const energyValueRounded = energySampledValueTemplate.value
parseInt(energySampledValueTemplate.value),
energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maximumEnergyRounded);
+ : Utils.getRandomFloatRounded(connectorMaximumEnergyRounded);
// Persist previous value on connector
if (
connector &&
)
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
- if (energyValueRounded > maximumEnergyRounded || debug) {
+ if (energyValueRounded > connectorMaximumEnergyRounded || debug) {
logger.error(
`${chargingStation.logPrefix()} MeterValues measurand ${
meterValue.sampledValue[sampledValuesIndex].measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: connectorId ${connectorId}, transaction ${
connector.transactionId
- }, value: ${energyValueRounded}/${maximumEnergyRounded}, duration: ${Utils.roundTo(
+ }, value: ${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${Utils.roundTo(
interval / (3600 * 1000),
4
)}h`