1 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
3 import { MeterValueContext
, MeterValueLocation
, MeterValueUnit
, OCPP16MeterValue
, OCPP16MeterValueMeasurand
, OCPP16MeterValuePhase
, OCPP16SampledValue
} from
'../../../types/ocpp/1.6/MeterValues';
5 import ChargingStation from
'../../ChargingStation';
6 import { SampledValueTemplate
} from
'../../../types/Connectors';
7 import Utils from
'../../../utils/Utils';
8 import logger from
'../../../utils/Logger';
10 export class OCPP16ServiceUtils
{
11 public static checkMeasurandPowerDivider(chargingStation
: ChargingStation
, measurandType
: OCPP16MeterValueMeasurand
): void {
12 if (Utils
.isUndefined(chargingStation
.stationInfo
.powerDivider
)) {
13 const errMsg
= `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
15 throw new Error(errMsg
);
16 } else if (chargingStation
.stationInfo
?.powerDivider
<= 0) {
17 const errMsg
= `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
19 throw new Error(errMsg
);
23 public static buildSampledValue(sampledValueTemplate
: SampledValueTemplate
, value
: number, context
?: MeterValueContext
, phase
?: OCPP16MeterValuePhase
): OCPP16SampledValue
{
24 const sampledValueValue
= value
?? (sampledValueTemplate
?.value
?? null);
25 const sampledValueContext
= context
?? (sampledValueTemplate
?.context
?? null);
26 const sampledValueLocation
= sampledValueTemplate
?.location
?? OCPP16ServiceUtils
.getMeasurandDefaultLocation(sampledValueTemplate
?.measurand
?? null);
27 const sampledValuePhase
= phase
?? (sampledValueTemplate
?.phase
?? null);
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
},
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
;
58 public static getMeasurandDefaultLocation(measurandType
: OCPP16MeterValueMeasurand
): MeterValueLocation
| undefined {
59 switch (measurandType
) {
60 case OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
:
61 return MeterValueLocation
.EV
;
65 public static buildTransactionBeginMeterValue(chargingStation
: ChargingStation
, connectorId
: number, meterBegin
: number): OCPP16MeterValue
{
66 const meterValue
: OCPP16MeterValue
= {
67 timestamp
: new Date().toISOString(),
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
));
77 public static buildTransactionEndMeterValue(chargingStation
: ChargingStation
, connectorId
: number, meterEnd
: number): OCPP16MeterValue
{
78 const meterValue
: OCPP16MeterValue
= {
79 timestamp
: new Date().toISOString(),
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
));
89 public static buildTransactionDataMeterValues(transactionBeginMeterValue
: OCPP16MeterValue
, transactionEndMeterValue
: OCPP16MeterValue
): OCPP16MeterValue
[] {
90 const meterValues
: OCPP16MeterValue
[] = [];
91 meterValues
.push(transactionBeginMeterValue
);
92 meterValues
.push(transactionEndMeterValue
);