const moduleName = 'OCPPServiceUtils'
+const SOC_MAXIMUM_VALUE = 100
+const UNIT_DIVIDER_KILO = 1000
+const MILLISECONDS_PER_HOUR = 3_600_000
+
export type Ajv = _Ajv.default
// eslint-disable-next-line @typescript-eslint/no-redeclare
const Ajv = _Ajv.default
return null
}
- const socMaximumValue = 100
+ const socMaximumValue = SOC_MAXIMUM_VALUE
const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0
const socSampledValueTemplateValue = isNotEmptyString(socSampledValueTemplate.value)
? getRandomFloatFluctuatedRounded(
}
}
-const validateSocMeasurandValue = (
+const validateMeasurandValue = (
chargingStation: ChargingStation,
connectorId: number,
- sampledValue: SampledValue,
- socMinimumValue: number,
- socMaximumValue: number,
- debug: boolean
+ value: number,
+ minValue: number,
+ maxValue: number,
+ measurand: MeterValueMeasurand | undefined,
+ debug: boolean,
+ options?: {
+ connectorStatus?: ConnectorStatus
+ interval?: number
+ phase?: MeterValuePhase
+ }
): void => {
- const connectorStatus = chargingStation.getConnectorStatus(connectorId)
- if (
- convertToInt(sampledValue.value) > socMaximumValue ||
- convertToInt(sampledValue.value) < socMinimumValue ||
- debug
- ) {
+ if (value > maxValue || value < minValue || debug) {
+ const connStatus = options?.connectorStatus ?? chargingStation.getConnectorStatus(connectorId)
+ const phaseStr = options?.phase != null ? `, phase ${options.phase as string}` : ''
+ const intervalStr =
+ options?.interval != null ? `, duration: ${options.interval.toString()}ms` : ''
logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateSocMeasurandValue: MeterValues measurand ${
- sampledValue.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+ `${chargingStation.logPrefix()} ${moduleName}.validateMeasurandValue: MeterValues measurand ${
+ measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- }: connector id ${connectorId.toString()}, transaction id ${connectorStatus?.transactionId?.toString()}, value: ${socMinimumValue.toString()}/${sampledValue.value.toString()}/${socMaximumValue.toString()}`
+ }: connector id ${connectorId.toString()}${phaseStr}, transaction id ${connStatus?.transactionId?.toString()}, value: ${minValue.toString()}/${value.toString()}/${maxValue.toString()}${intervalStr}`
)
}
}
connectorId: number,
meterValue: { sampledValue: TSampledValue[] },
mainVoltageData: { template: SampledValueTemplate; value: number },
- phase: number,
- buildVersionedSampledValue: (
- sampledValueTemplate: SampledValueTemplate,
- value: number,
- context?: MeterValueContext,
- phase?: MeterValuePhase
- ) => TSampledValue,
- measurandsKey?: ConfigurationKeyType,
- context?: MeterValueContext
-): void => {
- const stationInfo = chargingStation.stationInfo
- if (stationInfo == null) {
- return
- }
- const phaseLineToNeutralValue = `L${phase.toString()}-N` as MeterValuePhase
- const voltagePhaseLineToNeutralSampledValueTemplate = getSampledValueTemplate(
- chargingStation,
- connectorId,
- measurandsKey,
- MeterValueMeasurand.VOLTAGE,
- undefined,
- phaseLineToNeutralValue
- )
- let voltagePhaseLineToNeutralMeasurandValue: number | undefined
- if (voltagePhaseLineToNeutralSampledValueTemplate != null) {
- const voltagePhaseLineToNeutralSampledValueTemplateValue = isNotEmptyString(
- voltagePhaseLineToNeutralSampledValueTemplate.value
- )
- ? Number.parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
- : chargingStation.getVoltageOut()
- const fluctuationPhaseToNeutralPercent =
- voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT
- voltagePhaseLineToNeutralMeasurandValue = getRandomFloatFluctuatedRounded(
- voltagePhaseLineToNeutralSampledValueTemplateValue,
- fluctuationPhaseToNeutralPercent
- )
- }
- meterValue.sampledValue.push(
- buildVersionedSampledValue(
- voltagePhaseLineToNeutralSampledValueTemplate ?? mainVoltageData.template,
- voltagePhaseLineToNeutralMeasurandValue ?? mainVoltageData.value,
- context,
- phaseLineToNeutralValue
- )
- )
-}
-
-const addLineToLineVoltageToMeterValue = <TSampledValue extends SampledValue>(
- chargingStation: ChargingStation,
- connectorId: number,
- meterValue: { sampledValue: TSampledValue[] },
- mainVoltageData: { template: SampledValueTemplate; value: number },
- phase: number,
+ phaseLabel: MeterValuePhase,
+ nominalVoltage: number,
buildVersionedSampledValue: (
sampledValueTemplate: SampledValueTemplate,
value: number,
phase?: MeterValuePhase
) => TSampledValue,
measurandsKey?: ConfigurationKeyType,
- context?: MeterValueContext
+ context?: MeterValueContext,
+ noTemplateFallback?: number
): void => {
- const stationInfo = chargingStation.stationInfo
- if (stationInfo?.phaseLineToLineVoltageMeterValues !== true) {
- return
- }
- const phaseLineToLineValue = `L${phase.toString()}-L${
- (phase + 1) % chargingStation.getNumberOfPhases() !== 0
- ? ((phase + 1) % chargingStation.getNumberOfPhases()).toString()
- : chargingStation.getNumberOfPhases().toString()
- }` as MeterValuePhase
- const voltagePhaseLineToLineValueRounded = roundTo(
- Math.sqrt(chargingStation.getNumberOfPhases()) * chargingStation.getVoltageOut(),
- 2
- )
- const voltagePhaseLineToLineSampledValueTemplate = getSampledValueTemplate(
+ const phaseSampledValueTemplate = getSampledValueTemplate(
chargingStation,
connectorId,
measurandsKey,
MeterValueMeasurand.VOLTAGE,
undefined,
- phaseLineToLineValue
+ phaseLabel
)
- let voltagePhaseLineToLineMeasurandValue: number | undefined
- if (voltagePhaseLineToLineSampledValueTemplate != null) {
- const voltagePhaseLineToLineSampledValueTemplateValue = isNotEmptyString(
- voltagePhaseLineToLineSampledValueTemplate.value
- )
- ? Number.parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
- : voltagePhaseLineToLineValueRounded
- const fluctuationPhaseLineToLinePercent =
- voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ??
- Constants.DEFAULT_FLUCTUATION_PERCENT
- voltagePhaseLineToLineMeasurandValue = getRandomFloatFluctuatedRounded(
- voltagePhaseLineToLineSampledValueTemplateValue,
- fluctuationPhaseLineToLinePercent
+ let phaseMeasurandValue: number | undefined
+ if (phaseSampledValueTemplate != null) {
+ const templateValue = isNotEmptyString(phaseSampledValueTemplate.value)
+ ? Number.parseInt(phaseSampledValueTemplate.value)
+ : nominalVoltage
+ phaseMeasurandValue = getRandomFloatFluctuatedRounded(
+ templateValue,
+ phaseSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
)
}
meterValue.sampledValue.push(
buildVersionedSampledValue(
- voltagePhaseLineToLineSampledValueTemplate ?? mainVoltageData.template,
- voltagePhaseLineToLineMeasurandValue ?? voltagePhaseLineToLineValueRounded,
+ phaseSampledValueTemplate ?? mainVoltageData.template,
+ phaseMeasurandValue ?? noTemplateFallback ?? nominalVoltage,
context,
- phaseLineToLineValue
+ phaseLabel
)
)
}
}
checkMeasurandPowerDivider(chargingStation, energyTemplate.measurand)
- const unitDivider = energyTemplate.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1
+ const unitDivider = energyTemplate.unit === MeterValueUnit.KILO_WATT_HOUR ? UNIT_DIVIDER_KILO : 1
const connectorMaximumAvailablePower =
chargingStation.getConnectorMaximumAvailablePower(connectorId)
const connectorMaximumEnergyRounded = roundTo(
- (connectorMaximumAvailablePower * interval) / (3600 * 1000),
+ (connectorMaximumAvailablePower * interval) / MILLISECONDS_PER_HOUR,
2
)
const connectorMinimumEnergyRounded = roundTo(energyTemplate.minimumValue ?? 0, 2)
}
}
-const validateEnergyMeasurandValue = (
- chargingStation: ChargingStation,
- connectorId: number,
- sampledValue: SampledValue,
- energyValue: number,
- minValue: number,
- maxValue: number,
- interval: number,
- debug: boolean
-): void => {
- if (energyValue > maxValue || energyValue < minValue || debug) {
- const connectorStatus = chargingStation.getConnectorStatus(connectorId)
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateEnergyMeasurandValue: MeterValues measurand ${
- sampledValue.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- }: connector id ${connectorId.toString()}, transaction id ${connectorStatus?.transactionId?.toString()}, value: ${minValue.toString()}/${energyValue.toString()}/${maxValue.toString()}, duration: ${interval.toString()}ms`
- )
- }
-}
-
const buildPowerMeasurandValue = (
chargingStation: ChargingStation,
connectorId: number,
checkMeasurandPowerDivider(chargingStation, powerTemplate.measurand)
const powerValues: MeasurandValues = {} as MeasurandValues
- const unitDivider = powerTemplate.unit === MeterValueUnit.KILO_WATT ? 1000 : 1
+ const unitDivider = powerTemplate.unit === MeterValueUnit.KILO_WATT ? UNIT_DIVIDER_KILO : 1
const connectorMaximumAvailablePower =
chargingStation.getConnectorMaximumAvailablePower(connectorId)
const connectorMaximumPower = Math.round(connectorMaximumAvailablePower)
}
}
-const validatePowerMeasurandValue = (
- chargingStation: ChargingStation,
- connectorId: number,
- connectorStatus: ConnectorStatus | undefined,
- sampledValue: SampledValue,
- connectorMaximumPower: number,
- connectorMinimumPower: number,
- debug: boolean
-): void => {
- if (
- convertToFloat(sampledValue.value) > connectorMaximumPower ||
- convertToFloat(sampledValue.value) < connectorMinimumPower ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validatePowerMeasurandValue: MeterValues measurand ${
- sampledValue.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- }: connector id ${connectorId.toString()}, transaction id ${connectorStatus?.transactionId?.toString()}, value: ${connectorMinimumPower.toString()}/${sampledValue.value.toString()}/${connectorMaximumPower.toString()}`
- )
- }
-}
-
-const validateCurrentMeasurandValue = (
- chargingStation: ChargingStation,
- connectorId: number,
- connectorStatus: ConnectorStatus | undefined,
- sampledValue: SampledValue,
- connectorMaximumAmperage: number,
- connectorMinimumAmperage: number,
- debug: boolean
-): void => {
- if (
- convertToFloat(sampledValue.value) > connectorMaximumAmperage ||
- convertToFloat(sampledValue.value) < connectorMinimumAmperage ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateCurrentMeasurandValue: MeterValues measurand ${
- sampledValue.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- }: connector id ${connectorId.toString()}, transaction id ${connectorStatus?.transactionId?.toString()}, value: ${connectorMinimumAmperage.toString()}/${sampledValue.value.toString()}/${connectorMaximumAmperage.toString()}`
- )
- }
-}
-
-const validateCurrentMeasurandPhaseValue = (
- chargingStation: ChargingStation,
- connectorId: number,
- connectorStatus: ConnectorStatus | undefined,
- sampledValue: SampledValue,
- connectorMaximumAmperage: number,
- connectorMinimumAmperage: number,
- debug: boolean
-): void => {
- if (
- convertToFloat(sampledValue.value) > connectorMaximumAmperage ||
- convertToFloat(sampledValue.value) < connectorMinimumAmperage ||
- debug
- ) {
- logger.error(
- `${chargingStation.logPrefix()} ${moduleName}.validateCurrentMeasurandPhaseValue: MeterValues measurand ${
- sampledValue.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
- }: phase ${
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- sampledValue.phase
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
- }, connector id ${connectorId.toString()}, transaction id ${connectorStatus?.transactionId?.toString()}, value: ${connectorMinimumAmperage.toString()}/${sampledValue.value.toString()}/${connectorMaximumAmperage.toString()}`
- )
- }
-}
-
const buildCurrentMeasurandValue = (
chargingStation: ChargingStation,
connectorId: number,
context
)
meterValue.sampledValue.push(socSampledValue)
- validateSocMeasurandValue(
+ validateMeasurandValue(
chargingStation,
connectorId,
- socSampledValue,
+ convertToInt(socSampledValue.value),
socMeasurand.template.minimumValue ?? 0,
- 100,
+ SOC_MAXIMUM_VALUE,
+ socSampledValue.measurand,
debug
)
}
connectorId,
meterValue,
voltageMeasurand,
- phase,
- buildVersionedSampledValue,
- measurandsKey,
- context
- )
- addLineToLineVoltageToMeterValue(
- chargingStation,
- connectorId,
- meterValue,
- voltageMeasurand,
- phase,
+ `L${phase.toString()}-N` as MeterValuePhase,
+ chargingStation.getVoltageOut(),
buildVersionedSampledValue,
measurandsKey,
- context
+ context,
+ voltageMeasurand.value
)
+ if (chargingStation.stationInfo.phaseLineToLineVoltageMeterValues === true) {
+ const nextPhase =
+ (phase + 1) % chargingStation.getNumberOfPhases() !== 0
+ ? ((phase + 1) % chargingStation.getNumberOfPhases()).toString()
+ : chargingStation.getNumberOfPhases().toString()
+ const lineToLineLabel = `L${phase.toString()}-L${nextPhase}` as MeterValuePhase
+ const lineToLineNominalVoltage = roundTo(
+ Math.sqrt(chargingStation.getNumberOfPhases()) * chargingStation.getVoltageOut(),
+ 2
+ )
+ addPhaseVoltageToMeterValue(
+ chargingStation,
+ connectorId,
+ meterValue,
+ voltageMeasurand,
+ lineToLineLabel,
+ lineToLineNominalVoltage,
+ buildVersionedSampledValue,
+ measurandsKey,
+ context
+ )
+ }
}
}
// Power.Active.Import measurand
measurandsKey
)
if (powerMeasurand?.values.allPhases != null) {
- const unitDivider = powerMeasurand.template.unit === MeterValueUnit.KILO_WATT ? 1000 : 1
+ const unitDivider =
+ powerMeasurand.template.unit === MeterValueUnit.KILO_WATT ? UNIT_DIVIDER_KILO : 1
const connectorMaximumAvailablePower =
chargingStation.getConnectorMaximumAvailablePower(connectorId)
const connectorMaximumPower = Math.round(connectorMaximumAvailablePower)
buildVersionedSampledValue(powerMeasurand.template, powerMeasurand.values.allPhases, context)
)
const sampledValuesIndex = meterValue.sampledValue.length - 1
- validatePowerMeasurandValue(
+ validateMeasurandValue(
chargingStation,
connectorId,
- connectorStatus,
- meterValue.sampledValue[sampledValuesIndex],
- connectorMaximumPower / unitDivider,
+ convertToFloat(meterValue.sampledValue[sampledValuesIndex].value),
connectorMinimumPower / unitDivider,
- debug
+ connectorMaximumPower / unitDivider,
+ meterValue.sampledValue[sampledValuesIndex].measurand,
+ debug,
+ { connectorStatus }
)
if (chargingStation.getNumberOfPhases() === 3) {
const connectorMaximumPowerPerPhase = Math.round(
buildVersionedSampledValue(phaseTemplate, phasePowerValue, context, phaseValue)
)
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1
- validatePowerMeasurandValue(
+ validateMeasurandValue(
chargingStation,
connectorId,
- connectorStatus,
- meterValue.sampledValue[sampledValuesPerPhaseIndex],
- connectorMaximumPowerPerPhase / unitDivider,
+ convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value),
connectorMinimumPowerPerPhase / unitDivider,
- debug
+ connectorMaximumPowerPerPhase / unitDivider,
+ meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand,
+ debug,
+ { connectorStatus }
)
}
}
)
)
const sampledValuesIndex = meterValue.sampledValue.length - 1
- validateCurrentMeasurandValue(
+ validateMeasurandValue(
chargingStation,
connectorId,
- connectorStatus,
- meterValue.sampledValue[sampledValuesIndex],
- connectorMaximumAmperage,
+ convertToFloat(meterValue.sampledValue[sampledValuesIndex].value),
connectorMinimumAmperage,
- debug
+ connectorMaximumAmperage,
+ meterValue.sampledValue[sampledValuesIndex].measurand,
+ debug,
+ { connectorStatus }
)
for (
let phase = 1;
)
)
const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1
- validateCurrentMeasurandPhaseValue(
+ validateMeasurandValue(
chargingStation,
connectorId,
- connectorStatus,
- meterValue.sampledValue[sampledValuesPerPhaseIndex],
- connectorMaximumAmperage,
+ convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value),
connectorMinimumAmperage,
- debug
+ connectorMaximumAmperage,
+ meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand,
+ debug,
+ { connectorStatus, phase: meterValue.sampledValue[sampledValuesPerPhaseIndex].phase }
)
}
}
)
if (energyMeasurand != null) {
updateConnectorEnergyValues(connectorStatus, energyMeasurand.value)
- const unitDivider = energyMeasurand.template.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1
+ const unitDivider =
+ energyMeasurand.template.unit === MeterValueUnit.KILO_WATT_HOUR ? UNIT_DIVIDER_KILO : 1
const energySampledValue = buildVersionedSampledValue(
energyMeasurand.template,
roundTo(
const connectorMaximumAvailablePower =
chargingStation.getConnectorMaximumAvailablePower(connectorId)
const connectorMaximumEnergyRounded = roundTo(
- (connectorMaximumAvailablePower * interval) / (3600 * 1000),
+ (connectorMaximumAvailablePower * interval) / MILLISECONDS_PER_HOUR,
2
)
const connectorMinimumEnergyRounded = roundTo(energyMeasurand.template.minimumValue ?? 0, 2)
- validateEnergyMeasurandValue(
+ validateMeasurandValue(
chargingStation,
connectorId,
- energySampledValue,
energyMeasurand.value,
connectorMinimumEnergyRounded,
connectorMaximumEnergyRounded,
- interval,
- debug
+ energySampledValue.measurand,
+ debug,
+ { interval }
)
}
return meterValue as MeterValue
value: number
} => {
const sampledValueMeasurand =
- (sampledValueTemplate.measurand as MeterValueMeasurand | undefined) ?? getMeasurandDefault()
+ (sampledValueTemplate.measurand as MeterValueMeasurand | undefined) ??
+ MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
return {
context:
context ??
(sampledValueTemplate.context as MeterValueContext | undefined) ??
- getMeasurandDefaultContext(sampledValueMeasurand),
+ MeterValueContext.SAMPLE_PERIODIC,
location:
(sampledValueTemplate.location as MeterValueLocation | undefined) ??
getMeasurandDefaultLocation(sampledValueMeasurand),
}
}
-const getMeasurandDefaultContext = (measurandType: MeterValueMeasurand): MeterValueContext => {
- return MeterValueContext.SAMPLE_PERIODIC
-}
-
const getMeasurandDefaultLocation = (
measurandType: MeterValueMeasurand
): MeterValueLocation | undefined => {
}
}
-const getMeasurandDefault = (): MeterValueMeasurand => {
- return MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-}
-
const getMeasurandDefaultUnit = (
measurandType: MeterValueMeasurand
): MeterValueUnit | undefined => {