// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
+import { ACElectricUtils, DCElectricUtils } from '../utils/ElectricUtils';
import {
AvailabilityType,
BootNotificationRequest,
ConfigurationKey,
} from '../types/ChargingStationOcppConfiguration';
import ChargingStationTemplate, {
+ AmpereUnits,
CurrentType,
PowerUnits,
Voltage,
: defaultVoltageOut;
}
+ public getMaximumConfiguredPower(): number | undefined {
+ let maximumConfiguredPower =
+ (this.stationInfo['maxPower'] as number) ?? this.stationInfo.maximumPower;
+ if (this.getAmperageLimitation() < this.stationInfo.maximumAmperage) {
+ maximumConfiguredPower =
+ this.getCurrentOutType() === CurrentType.AC
+ ? ACElectricUtils.powerTotal(
+ this.getNumberOfPhases(),
+ this.getVoltageOut(),
+ this.getAmperageLimitation()
+ )
+ : DCElectricUtils.power(this.getVoltageOut(), this.getAmperageLimitation());
+ }
+ return maximumConfiguredPower;
+ }
+
public getTransactionIdTag(transactionId: number): string | undefined {
for (const connectorId of this.connectors.keys()) {
if (connectorId > 0 && this.getConnectorStatus(connectorId).transactionId === transactionId) {
if (!Utils.isEmptyArray(stationInfo.power)) {
stationInfo.power = stationInfo.power as number[];
const powerArrayRandomIndex = Math.floor(Utils.secureRandom() * stationInfo.power.length);
- stationInfo.maxPower =
+ stationInfo.maximumPower =
stationInfo.powerUnit === PowerUnits.KILO_WATT
? stationInfo.power[powerArrayRandomIndex] * 1000
: stationInfo.power[powerArrayRandomIndex];
} else {
stationInfo.power = stationInfo.power as number;
- stationInfo.maxPower =
+ stationInfo.maximumPower =
stationInfo.powerUnit === PowerUnits.KILO_WATT
? stationInfo.power * 1000
: stationInfo.power;
this.bootNotificationRequest = this.createBootNotificationRequest(this.stationInfo);
this.ocppConfiguration = this.getOcppConfiguration();
delete this.stationInfo.Configuration;
- this.saveStationInfo();
// Build connectors if needed
const maxConnectors = this.getMaxNumberOfConnectors();
if (maxConnectors <= 0) {
}
}
}
+ // The connectors attribute need to be initialized
+ this.stationInfo.maximumAmperage = this.getMaximumAmperage();
+ this.saveStationInfo();
// Avoid duplication of connectors related information in RAM
delete this.stationInfo.Connectors;
// Initialize transaction attributes on connectors
) {
this.deleteConfigurationKey(this.getSupervisionUrlOcppKey(), { save: false });
}
+ if (
+ this.stationInfo.amperageLimitationOcppKey &&
+ !this.getConfigurationKey(this.stationInfo.amperageLimitationOcppKey)
+ ) {
+ this.addConfigurationKey(
+ this.stationInfo.amperageLimitationOcppKey,
+ (this.stationInfo.maximumAmperage * this.getAmperageLimitationUnitDivider()).toString()
+ );
+ }
if (!this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)) {
this.addConfigurationKey(
StandardParametersKey.SupportedFeatureProfiles,
return maxConnectors;
}
+ private getMaximumAmperage(): number | undefined {
+ switch (this.getCurrentOutType()) {
+ case CurrentType.AC:
+ return ACElectricUtils.amperagePerPhaseFromPower(
+ this.getNumberOfPhases(),
+ (this.stationInfo['maxPower'] as number) ??
+ this.stationInfo.maximumPower / this.getNumberOfConnectors(),
+ this.getVoltageOut()
+ );
+ case CurrentType.DC:
+ return DCElectricUtils.amperage(this.stationInfo.maximumPower, this.getVoltageOut());
+ }
+ }
+
+ private getAmperageLimitationUnitDivider(): number {
+ let unitDivider = 1;
+ switch (this.stationInfo.amperageLimitationUnit) {
+ case AmpereUnits.DECI_AMPERE:
+ unitDivider = 10;
+ break;
+ case AmpereUnits.CENTI_AMPERE:
+ unitDivider = 100;
+ break;
+ case AmpereUnits.MILLI_AMPERE:
+ unitDivider = 1000;
+ break;
+ }
+ return unitDivider;
+ }
+
+ private getAmperageLimitation(): number | undefined {
+ if (
+ this.stationInfo.amperageLimitationOcppKey &&
+ this.getConfigurationKey(this.stationInfo.amperageLimitationOcppKey)
+ ) {
+ return (
+ Utils.convertToInt(
+ this.getConfigurationKey(this.stationInfo.amperageLimitationOcppKey).value
+ ) / this.getAmperageLimitationUnitDivider()
+ );
+ }
+ }
+
private async startMessageSequence(): Promise<void> {
if (this.stationInfo.autoRegister) {
await this.ocppRequestService.sendMessageHandler<BootNotificationResponse>(
} measurand value`;
const powerMeasurandValues = {} as MeasurandValues;
const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
- const maxPower = Math.round(
- chargingStation.stationInfo.maxPower / chargingStation.stationInfo.powerDivider
+ const maximumPower = Math.round(
+ chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider
);
- const maxPowerPerPhase = Math.round(
- chargingStation.stationInfo.maxPower /
+ const maximumPowerPerPhase = Math.round(
+ chargingStation.getMaximumConfiguredPower() /
chargingStation.stationInfo.powerDivider /
chargingStation.getNumberOfPhases()
);
powerMeasurandValues.L1 =
phase1FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
powerMeasurandValues.L2 =
phase2FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
powerMeasurandValues.L3 =
phase3FluctuatedValue ??
defaultFluctuatedPowerPerPhase ??
- Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+ Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
} else {
powerMeasurandValues.L1 = powerSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
powerSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maxPower / unitDivider);
+ : Utils.getRandomFloatRounded(maximumPower / unitDivider);
powerMeasurandValues.L2 = 0;
powerMeasurandValues.L3 = 0;
}
powerSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maxPower / unitDivider);
+ : Utils.getRandomFloatRounded(maximumPower / unitDivider);
break;
default:
logger.error(errMsg);
)
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
- const maxPowerRounded = Utils.roundTo(maxPower / unitDivider, 2);
+ const maxPowerRounded = Utils.roundTo(maximumPower / unitDivider, 2);
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPowerRounded ||
debug
)
);
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
- const maxPowerPerPhaseRounded = Utils.roundTo(maxPowerPerPhase / unitDivider, 2);
+ const maxPowerPerPhaseRounded = Utils.roundTo(maximumPowerPerPhase / unitDivider, 2);
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
maxPowerPerPhaseRounded ||
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
} measurand value`;
const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
- let maxAmperage: number;
+ let maximumAmperage: number;
switch (chargingStation.getCurrentOutType()) {
case CurrentType.AC:
- maxAmperage = ACElectricUtils.amperagePerPhaseFromPower(
+ maximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
chargingStation.getNumberOfPhases(),
- chargingStation.stationInfo.maxPower / chargingStation.stationInfo.powerDivider,
+ chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider,
chargingStation.getVoltageOut()
);
if (chargingStation.getNumberOfPhases() === 3) {
currentMeasurandValues.L1 =
phase1FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(maxAmperage);
+ Utils.getRandomFloatRounded(maximumAmperage);
currentMeasurandValues.L2 =
phase2FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(maxAmperage);
+ Utils.getRandomFloatRounded(maximumAmperage);
currentMeasurandValues.L3 =
phase3FluctuatedValue ??
defaultFluctuatedAmperagePerPhase ??
- Utils.getRandomFloatRounded(maxAmperage);
+ Utils.getRandomFloatRounded(maximumAmperage);
} else {
currentMeasurandValues.L1 = currentSampledValueTemplate.value
? Utils.getRandomFloatFluctuatedRounded(
currentSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maxAmperage);
+ : Utils.getRandomFloatRounded(maximumAmperage);
currentMeasurandValues.L2 = 0;
currentMeasurandValues.L3 = 0;
}
);
break;
case CurrentType.DC:
- maxAmperage = DCElectricUtils.amperage(
- chargingStation.stationInfo.maxPower / chargingStation.stationInfo.powerDivider,
+ maximumAmperage = DCElectricUtils.amperage(
+ chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider,
chargingStation.getVoltageOut()
);
currentMeasurandValues.allPhases = currentSampledValueTemplate.value
currentSampledValueTemplate.fluctuationPercent ??
Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maxAmperage);
+ : Utils.getRandomFloatRounded(maximumAmperage);
break;
default:
logger.error(errMsg);
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
if (
- Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxAmperage ||
+ Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maximumAmperage ||
debug
) {
logger.error(
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
meterValue.sampledValue[sampledValuesIndex].value
- }/${maxAmperage}`
+ }/${maximumAmperage}`
);
}
for (
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
if (
Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
- maxAmperage ||
+ maximumAmperage ||
debug
) {
logger.error(
meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
meterValue.sampledValue[sampledValuesPerPhaseIndex].value
- }/${maxAmperage}`
+ }/${maximumAmperage}`
);
}
}
);
const unitDivider =
energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
- const maxEnergyRounded = Utils.roundTo(
- ((chargingStation.stationInfo.maxPower / chargingStation.stationInfo.powerDivider) *
+ const maximumEnergyRounded = Utils.roundTo(
+ ((chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider) *
interval) /
(3600 * 1000),
2
parseInt(energySampledValueTemplate.value),
energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
)
- : Utils.getRandomFloatRounded(maxEnergyRounded);
+ : Utils.getRandomFloatRounded(maximumEnergyRounded);
// Persist previous value on connector
if (
connector &&
)
);
const sampledValuesIndex = meterValue.sampledValue.length - 1;
- if (energyValueRounded > maxEnergyRounded || debug) {
+ if (energyValueRounded > maximumEnergyRounded || debug) {
logger.error(
`${chargingStation.logPrefix()} MeterValues measurand ${
meterValue.sampledValue[sampledValuesIndex].measurand ??
OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
}: connectorId ${connectorId}, transaction ${
connector.transactionId
- }, value: ${energyValueRounded}/${maxEnergyRounded}, duration: ${Utils.roundTo(
+ }, value: ${energyValueRounded}/${maximumEnergyRounded}, duration: ${Utils.roundTo(
interval / (3600 * 1000),
4
)}h`