@citrineos/data
Version:
The OCPP data module which includes all persistence layer implementation.
375 lines • 16.7 kB
JavaScript
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
import { LocationEnum, MeasurandEnum, OCPP2_0_1, PhaseEnum, ReadingContextEnum, } from '@citrineos/base';
export class MeterValueMapper {
/**
* Converts native ReadingContextEnum to OCPP 2.0.1 ReadingContextEnumType
*/
static toReadingContextEnumType(context) {
if (!context)
return undefined;
switch (context) {
case 'Interruption.Begin':
return OCPP2_0_1.ReadingContextEnumType.Interruption_Begin;
case 'Interruption.End':
return OCPP2_0_1.ReadingContextEnumType.Interruption_End;
case 'Other':
return OCPP2_0_1.ReadingContextEnumType.Other;
case 'Sample.Clock':
return OCPP2_0_1.ReadingContextEnumType.Sample_Clock;
case 'Sample.Periodic':
return OCPP2_0_1.ReadingContextEnumType.Sample_Periodic;
case 'Transaction.Begin':
return OCPP2_0_1.ReadingContextEnumType.Transaction_Begin;
case 'Transaction.End':
return OCPP2_0_1.ReadingContextEnumType.Transaction_End;
case 'Trigger':
return OCPP2_0_1.ReadingContextEnumType.Trigger;
default:
return undefined;
}
}
/**
* Converts OCPP 2.0.1 ReadingContextEnumType to native ReadingContextEnum
*/
static fromReadingContextEnumType(context) {
if (!context)
return undefined;
switch (context) {
case OCPP2_0_1.ReadingContextEnumType.Interruption_Begin:
return 'Interruption.Begin';
case OCPP2_0_1.ReadingContextEnumType.Interruption_End:
return 'Interruption.End';
case OCPP2_0_1.ReadingContextEnumType.Other:
return 'Other';
case OCPP2_0_1.ReadingContextEnumType.Sample_Clock:
return 'Sample.Clock';
case OCPP2_0_1.ReadingContextEnumType.Sample_Periodic:
return 'Sample.Periodic';
case OCPP2_0_1.ReadingContextEnumType.Transaction_Begin:
return 'Transaction.Begin';
case OCPP2_0_1.ReadingContextEnumType.Transaction_End:
return 'Transaction.End';
case OCPP2_0_1.ReadingContextEnumType.Trigger:
return 'Trigger';
default:
return 'Sample.Periodic';
}
}
/**
* Converts native MeasurandEnum to OCPP 2.0.1 MeasurandEnumType
*/
static toMeasurandEnumType(measurand) {
if (!measurand)
return undefined;
switch (measurand) {
case 'Current.Export':
return OCPP2_0_1.MeasurandEnumType.Current_Export;
case 'Current.Import':
return OCPP2_0_1.MeasurandEnumType.Current_Import;
case 'Current.Offered':
return OCPP2_0_1.MeasurandEnumType.Current_Offered;
case 'Energy.Active.Export.Register':
return OCPP2_0_1.MeasurandEnumType.Energy_Active_Export_Register;
case 'Energy.Active.Import.Register':
return OCPP2_0_1.MeasurandEnumType.Energy_Active_Import_Register;
case 'Energy.Reactive.Export.Register':
return OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Export_Register;
case 'Energy.Reactive.Import.Register':
return OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Import_Register;
case 'Energy.Active.Export.Interval':
return OCPP2_0_1.MeasurandEnumType.Energy_Active_Export_Interval;
case 'Energy.Active.Import.Interval':
return OCPP2_0_1.MeasurandEnumType.Energy_Active_Import_Interval;
case 'Energy.Active.Net':
return OCPP2_0_1.MeasurandEnumType.Energy_Active_Net;
case 'Energy.Reactive.Export.Interval':
return OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Export_Interval;
case 'Energy.Reactive.Import.Interval':
return OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Import_Interval;
case 'Energy.Reactive.Net':
return OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Net;
case 'Energy.Apparent.Net':
return OCPP2_0_1.MeasurandEnumType.Energy_Apparent_Net;
case 'Energy.Apparent.Import':
return OCPP2_0_1.MeasurandEnumType.Energy_Apparent_Import;
case 'Energy.Apparent.Export':
return OCPP2_0_1.MeasurandEnumType.Energy_Apparent_Export;
case 'Frequency':
return OCPP2_0_1.MeasurandEnumType.Frequency;
case 'Power.Active.Export':
return OCPP2_0_1.MeasurandEnumType.Power_Active_Export;
case 'Power.Active.Import':
return OCPP2_0_1.MeasurandEnumType.Power_Active_Import;
case 'Power.Factor':
return OCPP2_0_1.MeasurandEnumType.Power_Factor;
case 'Power.Offered':
return OCPP2_0_1.MeasurandEnumType.Power_Offered;
case 'Power.Reactive.Export':
return OCPP2_0_1.MeasurandEnumType.Power_Reactive_Export;
case 'Power.Reactive.Import':
return OCPP2_0_1.MeasurandEnumType.Power_Reactive_Import;
case 'SoC':
return OCPP2_0_1.MeasurandEnumType.SoC;
case 'Voltage':
return OCPP2_0_1.MeasurandEnumType.Voltage;
default:
// Note: Native enum measurands not supported in OCPP 2.0.1:
// Temperature, RPM - from OCPP 1.6
return undefined;
}
}
/**
* Converts OCPP 2.0.1 MeasurandEnumType to native MeasurandEnum
*/
static fromMeasurandEnumType(measurand) {
if (!measurand)
return undefined;
switch (measurand) {
case OCPP2_0_1.MeasurandEnumType.Current_Export:
return 'Current.Export';
case OCPP2_0_1.MeasurandEnumType.Current_Import:
return 'Current.Import';
case OCPP2_0_1.MeasurandEnumType.Current_Offered:
return 'Current.Offered';
case OCPP2_0_1.MeasurandEnumType.Energy_Active_Export_Register:
return 'Energy.Active.Export.Register';
case OCPP2_0_1.MeasurandEnumType.Energy_Active_Import_Register:
return 'Energy.Active.Import.Register';
case OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Export_Register:
return 'Energy.Reactive.Export.Register';
case OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Import_Register:
return 'Energy.Reactive.Import.Register';
case OCPP2_0_1.MeasurandEnumType.Energy_Active_Export_Interval:
return 'Energy.Active.Export.Interval';
case OCPP2_0_1.MeasurandEnumType.Energy_Active_Import_Interval:
return 'Energy.Active.Import.Interval';
case OCPP2_0_1.MeasurandEnumType.Energy_Active_Net:
return 'Energy.Active.Net';
case OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Export_Interval:
return 'Energy.Reactive.Export.Interval';
case OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Import_Interval:
return 'Energy.Reactive.Import.Interval';
case OCPP2_0_1.MeasurandEnumType.Energy_Reactive_Net:
return 'Energy.Reactive.Net';
case OCPP2_0_1.MeasurandEnumType.Energy_Apparent_Net:
return 'Energy.Apparent.Net';
case OCPP2_0_1.MeasurandEnumType.Energy_Apparent_Import:
return 'Energy.Apparent.Import';
case OCPP2_0_1.MeasurandEnumType.Energy_Apparent_Export:
return 'Energy.Apparent.Export';
case OCPP2_0_1.MeasurandEnumType.Frequency:
return 'Frequency';
case OCPP2_0_1.MeasurandEnumType.Power_Active_Export:
return 'Power.Active.Export';
case OCPP2_0_1.MeasurandEnumType.Power_Active_Import:
return 'Power.Active.Import';
case OCPP2_0_1.MeasurandEnumType.Power_Factor:
return 'Power.Factor';
case OCPP2_0_1.MeasurandEnumType.Power_Offered:
return 'Power.Offered';
case OCPP2_0_1.MeasurandEnumType.Power_Reactive_Export:
return 'Power.Reactive.Export';
case OCPP2_0_1.MeasurandEnumType.Power_Reactive_Import:
return 'Power.Reactive.Import';
case OCPP2_0_1.MeasurandEnumType.SoC:
return 'SoC';
case OCPP2_0_1.MeasurandEnumType.Voltage:
return 'Voltage';
default:
return 'Energy.Active.Import.Register';
}
}
/**
* Converts native LocationEnum to OCPP 2.0.1 LocationEnumType
*/
static toLocationEnumType(location) {
if (!location)
return undefined;
switch (location) {
case 'Body':
return OCPP2_0_1.LocationEnumType.Body;
case 'Cable':
return OCPP2_0_1.LocationEnumType.Cable;
case 'EV':
return OCPP2_0_1.LocationEnumType.EV;
case 'Inlet':
return OCPP2_0_1.LocationEnumType.Inlet;
case 'Outlet':
return OCPP2_0_1.LocationEnumType.Outlet;
default:
return undefined;
}
}
/**
* Converts OCPP 2.0.1 LocationEnumType to native LocationEnum
*/
static fromLocationEnumType(location) {
if (!location)
return undefined;
switch (location) {
case OCPP2_0_1.LocationEnumType.Body:
return 'Body';
case OCPP2_0_1.LocationEnumType.Cable:
return 'Cable';
case OCPP2_0_1.LocationEnumType.EV:
return 'EV';
case OCPP2_0_1.LocationEnumType.Inlet:
return 'Inlet';
case OCPP2_0_1.LocationEnumType.Outlet:
return 'Outlet';
default:
return 'Outlet';
}
}
/**
* Converts native PhaseEnum to OCPP 2.0.1 PhaseEnumType
*/
static toPhaseEnumType(phase) {
if (!phase)
return undefined;
switch (phase) {
case 'L1':
return OCPP2_0_1.PhaseEnumType.L1;
case 'L2':
return OCPP2_0_1.PhaseEnumType.L2;
case 'L3':
return OCPP2_0_1.PhaseEnumType.L3;
case 'N':
return OCPP2_0_1.PhaseEnumType.N;
case 'L1-N':
return OCPP2_0_1.PhaseEnumType.L1_N;
case 'L2-N':
return OCPP2_0_1.PhaseEnumType.L2_N;
case 'L3-N':
return OCPP2_0_1.PhaseEnumType.L3_N;
case 'L1-L2':
return OCPP2_0_1.PhaseEnumType.L1_L2;
case 'L2-L3':
return OCPP2_0_1.PhaseEnumType.L2_L3;
case 'L3-L1':
return OCPP2_0_1.PhaseEnumType.L3_L1;
default:
return undefined;
}
}
/**
* Converts OCPP 2.0.1 PhaseEnumType to native PhaseEnum
*/
static fromPhaseEnumType(phase) {
if (!phase)
return undefined;
switch (phase) {
case OCPP2_0_1.PhaseEnumType.L1:
return 'L1';
case OCPP2_0_1.PhaseEnumType.L2:
return 'L2';
case OCPP2_0_1.PhaseEnumType.L3:
return 'L3';
case OCPP2_0_1.PhaseEnumType.N:
return 'N';
case OCPP2_0_1.PhaseEnumType.L1_N:
return 'L1-N';
case OCPP2_0_1.PhaseEnumType.L2_N:
return 'L2-N';
case OCPP2_0_1.PhaseEnumType.L3_N:
return 'L3-N';
case OCPP2_0_1.PhaseEnumType.L1_L2:
return 'L1-L2';
case OCPP2_0_1.PhaseEnumType.L2_L3:
return 'L2-L3';
case OCPP2_0_1.PhaseEnumType.L3_L1:
return 'L3-L1';
default:
return undefined;
}
}
static toMeterValueType(meterValue) {
return {
timestamp: meterValue.timestamp,
sampledValue: MeterValueMapper.toSampledValueTypes(meterValue.sampledValue),
};
}
static toSampledValueTypes(sampledValues) {
if (!(sampledValues instanceof Array) || sampledValues.length === 0) {
throw new Error(`Invalid sampledValues: ${JSON.stringify(sampledValues)}`);
}
const sampledValueTypes = [];
for (const sampledValue of sampledValues) {
const measurand = MeterValueMapper.toMeasurandEnumType(sampledValue.measurand);
if (measurand !== undefined) {
sampledValueTypes.push({
value: sampledValue.value,
context: MeterValueMapper.toReadingContextEnumType(sampledValue.context),
measurand: measurand,
phase: MeterValueMapper.toPhaseEnumType(sampledValue.phase),
location: MeterValueMapper.toLocationEnumType(sampledValue.location),
signedMeterValue: sampledValue.signedMeterValue
? {
signedMeterData: sampledValue.signedMeterValue.signedMeterData,
signingMethod: sampledValue.signedMeterValue.signingMethod,
encodingMethod: sampledValue.signedMeterValue.encodingMethod,
publicKey: sampledValue.signedMeterValue.publicKey,
}
: undefined,
unitOfMeasure: sampledValue.unitOfMeasure
? {
unit: sampledValue.unitOfMeasure.unit,
multiplier: sampledValue.unitOfMeasure.multiplier,
}
: undefined,
});
}
else {
console.warn(`Unsupported measurand for OCPP 2.0.1: ${sampledValue.measurand}`);
}
}
return sampledValueTypes;
}
/**
* Converts OCPP2_0_1.SampledValueType[] back to SampledValue[]
*/
static fromSampledValueTypes(sampledValueTypes) {
if (!Array.isArray(sampledValueTypes) || sampledValueTypes.length === 0) {
throw new Error(`Invalid sampledValueTypes: ${JSON.stringify(sampledValueTypes)}`);
}
const sampledValues = [];
for (const sampledValueType of sampledValueTypes) {
const sampledValue = {
value: sampledValueType.value,
context: MeterValueMapper.fromReadingContextEnumType(sampledValueType.context),
measurand: MeterValueMapper.fromMeasurandEnumType(sampledValueType.measurand),
phase: MeterValueMapper.fromPhaseEnumType(sampledValueType.phase),
location: MeterValueMapper.fromLocationEnumType(sampledValueType.location),
};
if (sampledValueType.signedMeterValue) {
sampledValue.signedMeterValue = {
signedMeterData: sampledValueType.signedMeterValue.signedMeterData,
signingMethod: sampledValueType.signedMeterValue.signingMethod,
encodingMethod: sampledValueType.signedMeterValue.encodingMethod,
publicKey: sampledValueType.signedMeterValue.publicKey,
};
}
if (sampledValueType.unitOfMeasure) {
sampledValue.unitOfMeasure = {
unit: sampledValueType.unitOfMeasure.unit ||
(sampledValue.measurand?.startsWith('Energy') ? 'Wh' : undefined),
multiplier: sampledValueType.unitOfMeasure.multiplier || 0,
};
}
sampledValues.push(sampledValue);
}
return sampledValues;
}
/**
* Converts OCPP2_0_1.MeterValueType back to a partial MeterValue structure
*/
static fromMeterValueType(meterValueType) {
return {
timestamp: meterValueType.timestamp,
sampledValue: MeterValueMapper.fromSampledValueTypes(meterValueType.sampledValue),
};
}
}
//# sourceMappingURL=MeterValueMapper.js.map