- // Power.Active.Import measurand
- const powerSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
- );
- let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
- if (chargingStation.getNumberOfPhases() === 3) {
- powerPerPhaseSampledValueTemplates = {
- L1: OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
- OCPP16MeterValuePhase.L1_N,
- ),
- L2: OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
- OCPP16MeterValuePhase.L2_N,
- ),
- L3: OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
- OCPP16MeterValuePhase.L3_N,
- ),
- };
- }
- if (powerSampledValueTemplate) {
- OCPP16ServiceUtils.checkMeasurandPowerDivider(
- chargingStation,
- powerSampledValueTemplate.measurand!,
- );
- const errMsg = `MeterValues measurand ${
- powerSampledValueTemplate.measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: Unknown ${chargingStation.getCurrentOutType()} currentOutType in template file ${
- chargingStation.templateFile
- }, cannot calculate ${
- powerSampledValueTemplate.measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- } measurand value`;
- const powerMeasurandValues: MeasurandValues = {} as MeasurandValues;
- const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
- const connectorMaximumAvailablePower =
- chargingStation.getConnectorMaximumAvailablePower(connectorId);
- const connectorMaximumPower = Math.round(connectorMaximumAvailablePower);
- const connectorMaximumPowerPerPhase = Math.round(
- connectorMaximumAvailablePower / chargingStation.getNumberOfPhases(),
- );
- const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue!) ?? 0;
- const connectorMinimumPowerPerPhase = Math.round(
- connectorMinimumPower / chargingStation.getNumberOfPhases(),
- );
- switch (chargingStation.getCurrentOutType()) {
- case CurrentType.AC:
- if (chargingStation.getNumberOfPhases() === 3) {
- const defaultFluctuatedPowerPerPhase =
- powerSampledValueTemplate.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- powerSampledValueTemplate.value,
- connectorMaximumPower / unitDivider,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ) / chargingStation.getNumberOfPhases(),
- powerSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- const phase1FluctuatedValue =
- powerPerPhaseSampledValueTemplates.L1?.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- powerPerPhaseSampledValueTemplates.L1.value,
- connectorMaximumPowerPerPhase / unitDivider,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- powerPerPhaseSampledValueTemplates.L1.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- const phase2FluctuatedValue =
- powerPerPhaseSampledValueTemplates.L2?.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- powerPerPhaseSampledValueTemplates.L2.value,
- connectorMaximumPowerPerPhase / unitDivider,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- powerPerPhaseSampledValueTemplates.L2.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- const phase3FluctuatedValue =
- powerPerPhaseSampledValueTemplates.L3?.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- powerPerPhaseSampledValueTemplates.L3.value,
- connectorMaximumPowerPerPhase / unitDivider,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- powerPerPhaseSampledValueTemplates.L3.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- powerMeasurandValues.L1 =
- (phase1FluctuatedValue as number) ??
- (defaultFluctuatedPowerPerPhase as number) ??
- getRandomFloatRounded(
- connectorMaximumPowerPerPhase / unitDivider,
- connectorMinimumPowerPerPhase / unitDivider,
- );
- powerMeasurandValues.L2 =
- (phase2FluctuatedValue as number) ??
- (defaultFluctuatedPowerPerPhase as number) ??
- getRandomFloatRounded(
- connectorMaximumPowerPerPhase / unitDivider,
- connectorMinimumPowerPerPhase / unitDivider,
- );
- powerMeasurandValues.L3 =
- (phase3FluctuatedValue as number) ??
- (defaultFluctuatedPowerPerPhase as number) ??
- getRandomFloatRounded(
- connectorMaximumPowerPerPhase / unitDivider,
- connectorMinimumPowerPerPhase / unitDivider,
- );
- } else {
- powerMeasurandValues.L1 = powerSampledValueTemplate.value
- ? getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- powerSampledValueTemplate.value,
- connectorMaximumPower / unitDivider,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- powerSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- )
- : getRandomFloatRounded(
- connectorMaximumPower / unitDivider,
- connectorMinimumPower / unitDivider,
- );
- powerMeasurandValues.L2 = 0;
- powerMeasurandValues.L3 = 0;
- }
- powerMeasurandValues.allPhases = roundTo(
- powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3,
- 2,
- );
- break;
- case CurrentType.DC:
- powerMeasurandValues.allPhases = powerSampledValueTemplate.value
- ? getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- powerSampledValueTemplate.value,
- connectorMaximumPower / unitDivider,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- powerSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- )
- : getRandomFloatRounded(
- connectorMaximumPower / unitDivider,
- connectorMinimumPower / unitDivider,
- );
- break;
- default:
- logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
- throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
- }
- meterValue.sampledValue.push(
- OCPP16ServiceUtils.buildSampledValue(
- powerSampledValueTemplate,
- powerMeasurandValues.allPhases,
- ),
- );
- const sampledValuesIndex = meterValue.sampledValue.length - 1;
- const connectorMaximumPowerRounded = roundTo(connectorMaximumPower / unitDivider, 2);
- const connectorMinimumPowerRounded = roundTo(connectorMinimumPower / unitDivider, 2);
- if (
- convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
- connectorMaximumPowerRounded ||
- convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
- connectorMinimumPowerRounded ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} MeterValues measurand ${
- meterValue.sampledValue[sampledValuesIndex].measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerRounded}/${
- meterValue.sampledValue[sampledValuesIndex].value
- }/${connectorMaximumPowerRounded}`,
- );
- }
- for (
- let phase = 1;
- chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
- phase++
- ) {
- const phaseValue = `L${phase}-N`;
- meterValue.sampledValue.push(
- OCPP16ServiceUtils.buildSampledValue(
- powerPerPhaseSampledValueTemplates[
- `L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates
- ]! ?? powerSampledValueTemplate,
- powerMeasurandValues[`L${phase}` as keyof MeasurandPerPhaseSampledValueTemplates],
- undefined,
- phaseValue as OCPP16MeterValuePhase,
- ),
- );
- const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
- const connectorMaximumPowerPerPhaseRounded = roundTo(
- connectorMaximumPowerPerPhase / unitDivider,
- 2,
- );
- const connectorMinimumPowerPerPhaseRounded = roundTo(
- connectorMinimumPowerPerPhase / unitDivider,
- 2,
- );
- if (
- convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
- connectorMaximumPowerPerPhaseRounded ||
- convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
- connectorMinimumPowerPerPhaseRounded ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} MeterValues measurand ${
- meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: phase ${
- meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
- }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumPowerPerPhaseRounded}/${
- meterValue.sampledValue[sampledValuesPerPhaseIndex].value
- }/${connectorMaximumPowerPerPhaseRounded}`,
- );
- }
- }
- }
- // Current.Import measurand
- const currentSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.CURRENT_IMPORT,
- );
- let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
- if (chargingStation.getNumberOfPhases() === 3) {
- currentPerPhaseSampledValueTemplates = {
- L1: OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.CURRENT_IMPORT,
- OCPP16MeterValuePhase.L1,
- ),
- L2: OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.CURRENT_IMPORT,
- OCPP16MeterValuePhase.L2,
- ),
- L3: OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- OCPP16MeterValueMeasurand.CURRENT_IMPORT,
- OCPP16MeterValuePhase.L3,
- ),
- };
- }
- if (currentSampledValueTemplate) {
- OCPP16ServiceUtils.checkMeasurandPowerDivider(
- chargingStation,
- currentSampledValueTemplate.measurand!,
- );
- const errMsg = `MeterValues measurand ${
- currentSampledValueTemplate.measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: Unknown ${chargingStation.getCurrentOutType()} currentOutType in template file ${
- chargingStation.templateFile
- }, cannot calculate ${
- currentSampledValueTemplate.measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- } measurand value`;
- const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
- const connectorMaximumAvailablePower =
- chargingStation.getConnectorMaximumAvailablePower(connectorId);
- const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0;
- let connectorMaximumAmperage: number;
- switch (chargingStation.getCurrentOutType()) {
- case CurrentType.AC:
- connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
- chargingStation.getNumberOfPhases(),
- connectorMaximumAvailablePower,
- chargingStation.getVoltageOut(),
- );
- if (chargingStation.getNumberOfPhases() === 3) {
- const defaultFluctuatedAmperagePerPhase =
- currentSampledValueTemplate.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- currentSampledValueTemplate.value,
- connectorMaximumAmperage,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- currentSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- const phase1FluctuatedValue =
- currentPerPhaseSampledValueTemplates.L1?.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- currentPerPhaseSampledValueTemplates.L1.value,
- connectorMaximumAmperage,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- currentPerPhaseSampledValueTemplates.L1.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- const phase2FluctuatedValue =
- currentPerPhaseSampledValueTemplates.L2?.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- currentPerPhaseSampledValueTemplates.L2.value,
- connectorMaximumAmperage,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- currentPerPhaseSampledValueTemplates.L2.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- const phase3FluctuatedValue =
- currentPerPhaseSampledValueTemplates.L3?.value &&
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- currentPerPhaseSampledValueTemplates.L3.value,
- connectorMaximumAmperage,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- currentPerPhaseSampledValueTemplates.L3.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- );
- currentMeasurandValues.L1 =
- (phase1FluctuatedValue as number) ??
- (defaultFluctuatedAmperagePerPhase as number) ??
- getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
- currentMeasurandValues.L2 =
- (phase2FluctuatedValue as number) ??
- (defaultFluctuatedAmperagePerPhase as number) ??
- getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
- currentMeasurandValues.L3 =
- (phase3FluctuatedValue as number) ??
- (defaultFluctuatedAmperagePerPhase as number) ??
- getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
- } else {
- currentMeasurandValues.L1 = currentSampledValueTemplate.value
- ? getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- currentSampledValueTemplate.value,
- connectorMaximumAmperage,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- currentSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- )
- : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
- currentMeasurandValues.L2 = 0;
- currentMeasurandValues.L3 = 0;
- }
- currentMeasurandValues.allPhases = roundTo(
- (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) /
- chargingStation.getNumberOfPhases(),
- 2,
- );
- break;
- case CurrentType.DC:
- connectorMaximumAmperage = DCElectricUtils.amperage(
- connectorMaximumAvailablePower,
- chargingStation.getVoltageOut(),
- );
- currentMeasurandValues.allPhases = currentSampledValueTemplate.value
- ? getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- currentSampledValueTemplate.value,
- connectorMaximumAmperage,
- { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() },
- ),
- currentSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT,
- )
- : getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
- break;
- default:
- logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
- throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
- }
- meterValue.sampledValue.push(
- OCPP16ServiceUtils.buildSampledValue(
- currentSampledValueTemplate,
- currentMeasurandValues.allPhases,
- ),
- );
- const sampledValuesIndex = meterValue.sampledValue.length - 1;
- if (
- convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
- connectorMaximumAmperage ||
- convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
- connectorMinimumAmperage ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} MeterValues measurand ${
- meterValue.sampledValue[sampledValuesIndex].measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
- meterValue.sampledValue[sampledValuesIndex].value
- }/${connectorMaximumAmperage}`,
- );
- }
- for (
- let phase = 1;
- chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
- phase++
- ) {
- const phaseValue = `L${phase}`;
- meterValue.sampledValue.push(
- OCPP16ServiceUtils.buildSampledValue(
- currentPerPhaseSampledValueTemplates[
- phaseValue as keyof MeasurandPerPhaseSampledValueTemplates
- ]! ?? currentSampledValueTemplate,
- currentMeasurandValues[phaseValue as keyof MeasurandPerPhaseSampledValueTemplates],
- undefined,
- phaseValue as OCPP16MeterValuePhase,
- ),
- );
- const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
- if (
- convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
- connectorMaximumAmperage ||
- convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
- connectorMinimumAmperage ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} MeterValues measurand ${
- meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: phase ${
- meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
- }, connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${connectorMinimumAmperage}/${
- meterValue.sampledValue[sampledValuesPerPhaseIndex].value
- }/${connectorMaximumAmperage}`,
- );
- }
- }
- }
- // Energy.Active.Import.Register measurand (default)
- const energySampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
- chargingStation,
- connectorId,
- );
- if (energySampledValueTemplate) {
- OCPP16ServiceUtils.checkMeasurandPowerDivider(
- chargingStation,
- energySampledValueTemplate.measurand!,
- );
- const unitDivider =
- energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
- const connectorMaximumAvailablePower =
- chargingStation.getConnectorMaximumAvailablePower(connectorId);
- const connectorMaximumEnergyRounded = roundTo(
- (connectorMaximumAvailablePower * interval) / (3600 * 1000),
- 2,
- );
- const energyValueRounded = energySampledValueTemplate.value
- ? // Cumulate the fluctuated value around the static one
- getRandomFloatFluctuatedRounded(
- OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
- energySampledValueTemplate.value,
- connectorMaximumEnergyRounded,
- {
- limitationEnabled: chargingStation.getCustomValueLimitationMeterValues(),
- unitMultiplier: unitDivider,
- },
- ),
- energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT,
- )
- : getRandomFloatRounded(connectorMaximumEnergyRounded);
- // Persist previous value on connector
- if (connector) {
- if (
- isNullOrUndefined(connector.energyActiveImportRegisterValue) === false &&
- connector.energyActiveImportRegisterValue! >= 0 &&
- isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) === false &&
- connector.transactionEnergyActiveImportRegisterValue! >= 0
- ) {
- connector.energyActiveImportRegisterValue! += energyValueRounded;
- connector.transactionEnergyActiveImportRegisterValue! += energyValueRounded;
- } else {
- connector.energyActiveImportRegisterValue = 0;
- connector.transactionEnergyActiveImportRegisterValue = 0;
- }
- }
- meterValue.sampledValue.push(
- OCPP16ServiceUtils.buildSampledValue(
- energySampledValueTemplate,
- roundTo(
- chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) /
- unitDivider,
- 2,
- ),
- ),
- );
- const sampledValuesIndex = meterValue.sampledValue.length - 1;
- if (energyValueRounded > connectorMaximumEnergyRounded || debug) {
- logger.error(
- `${chargingStation.logPrefix()} MeterValues measurand ${
- meterValue.sampledValue[sampledValuesIndex].measurand ??
- OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: connector id ${connectorId}, transaction id ${connector?.transactionId}, value: ${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${interval}ms`,
- );
- }
- }
- return meterValue;
- }
-
- public static buildTransactionBeginMeterValue(
- chargingStation: ChargingStation,
- connectorId: number,
- meterStart: number,
- ): OCPP16MeterValue {
- const meterValue: OCPP16MeterValue = {
- timestamp: new Date(),
- sampledValue: [],
- };