Properly handle charging profiles set a remote start transaction.
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ServiceUtils.ts
1 import { MeterValueContext, MeterValueLocation, MeterValueUnit, OCPP16MeterValue, OCPP16MeterValueMeasurand, OCPP16MeterValuePhase, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues';
2
3 import ChargingStation from '../../ChargingStation';
4 import { SampledValueTemplate } from '../../../types/Connectors';
5 import Utils from '../../../utils/Utils';
6 import logger from '../../../utils/Logger';
7
8 export class OCPP16ServiceUtils {
9 public static checkMeasurandPowerDivider(chargingStation: ChargingStation, measurandType: OCPP16MeterValueMeasurand): void {
10 if (Utils.isUndefined(chargingStation.stationInfo.powerDivider)) {
11 const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
12 logger.error(errMsg);
13 throw Error(errMsg);
14 } else if (chargingStation.stationInfo?.powerDivider <= 0) {
15 const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
16 logger.error(errMsg);
17 throw Error(errMsg);
18 }
19 }
20
21 public static buildSampledValue(sampledValueTemplate: SampledValueTemplate, value: number, context?: MeterValueContext, phase?: OCPP16MeterValuePhase): OCPP16SampledValue {
22 const sampledValueValue = value ?? (sampledValueTemplate.value ?? null);
23 const sampledValueContext = context ?? (sampledValueTemplate.context ?? null);
24 const sampledValueLocation = sampledValueTemplate.location
25 ? sampledValueTemplate.location
26 : OCPP16ServiceUtils.getMeasurandDefaultLocation(sampledValueTemplate.measurand ?? null);
27 const sampledValuePhase = phase ?? (sampledValueTemplate.phase ?? null);
28 return {
29 ...!Utils.isNullOrUndefined(sampledValueTemplate.unit) && { unit: sampledValueTemplate.unit },
30 ...!Utils.isNullOrUndefined(sampledValueContext) && { context: sampledValueContext },
31 ...!Utils.isNullOrUndefined(sampledValueTemplate.measurand) && { measurand: sampledValueTemplate.measurand },
32 ...!Utils.isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation },
33 ...!Utils.isNullOrUndefined(sampledValueValue) && { value: sampledValueValue.toString() },
34 ...!Utils.isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase },
35 };
36 }
37
38 public static getMeasurandDefaultUnit(measurandType: OCPP16MeterValueMeasurand): MeterValueUnit | undefined {
39 switch (measurandType) {
40 case OCPP16MeterValueMeasurand.CURRENT_EXPORT:
41 case OCPP16MeterValueMeasurand.CURRENT_IMPORT:
42 case OCPP16MeterValueMeasurand.CURRENT_OFFERED:
43 return MeterValueUnit.AMP;
44 case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_EXPORT_REGISTER:
45 case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER:
46 return MeterValueUnit.WATT_HOUR;
47 case OCPP16MeterValueMeasurand.POWER_ACTIVE_EXPORT:
48 case OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT:
49 case OCPP16MeterValueMeasurand.POWER_OFFERED:
50 return MeterValueUnit.WATT;
51 case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
52 return MeterValueUnit.PERCENT;
53 case OCPP16MeterValueMeasurand.VOLTAGE:
54 return MeterValueUnit.VOLT;
55 }
56 }
57
58 public static getMeasurandDefaultLocation(measurandType: OCPP16MeterValueMeasurand): MeterValueLocation | undefined {
59 switch (measurandType) {
60 case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
61 return MeterValueLocation.EV;
62 }
63 }
64
65 public static buildTransactionBeginMeterValue(chargingStation: ChargingStation, connectorId: number, meterBegin: number): OCPP16MeterValue {
66 const meterValue: OCPP16MeterValue = {
67 timestamp: new Date().toISOString(),
68 sampledValue: [],
69 };
70 // Energy.Active.Import.Register measurand (default)
71 const sampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
72 const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
73 meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(sampledValueTemplate, Utils.roundTo(meterBegin / unitDivider, 4), MeterValueContext.TRANSACTION_BEGIN));
74 return meterValue;
75 }
76
77 public static buildTransactionEndMeterValue(chargingStation: ChargingStation, connectorId: number, meterEnd: number): OCPP16MeterValue {
78 const meterValue: OCPP16MeterValue = {
79 timestamp: new Date().toISOString(),
80 sampledValue: [],
81 };
82 // Energy.Active.Import.Register measurand (default)
83 const sampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
84 const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
85 meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(sampledValueTemplate, Utils.roundTo(meterEnd / unitDivider, 4), MeterValueContext.TRANSACTION_END));
86 return meterValue;
87 }
88
89 public static buildTransactionDataMeterValues(transactionBeginMeterValue: OCPP16MeterValue, transactionEndMeterValue: OCPP16MeterValue): OCPP16MeterValue[] {
90 const meterValues: OCPP16MeterValue[] = [];
91 meterValues.push(transactionBeginMeterValue);
92 meterValues.push(transactionEndMeterValue);
93 return meterValues;
94 }
95 }