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 { ErrorType
} from
'../../../types/ocpp/ErrorType';
7 import OCPPError from
'../OCPPError';
8 import { SampledValueTemplate
} from
'../../../types/Connectors';
9 import Utils from
'../../../utils/Utils';
10 import logger from
'../../../utils/Logger';
12 export class OCPP16ServiceUtils
{
13 public static checkMeasurandPowerDivider(chargingStation
: ChargingStation
, measurandType
: OCPP16MeterValueMeasurand
): void {
14 if (Utils
.isUndefined(chargingStation
.stationInfo
.powerDivider
)) {
15 const errMsg
= `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
17 throw new OCPPError(ErrorType
.INTERNAL_ERROR
, errMsg
);
18 } else if (chargingStation
.stationInfo
?.powerDivider
<= 0) {
19 const errMsg
= `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
21 throw new OCPPError(ErrorType
.INTERNAL_ERROR
, errMsg
);
25 public static buildSampledValue(sampledValueTemplate
: SampledValueTemplate
, value
: number, context
?: MeterValueContext
, phase
?: OCPP16MeterValuePhase
): OCPP16SampledValue
{
26 const sampledValueValue
= value
?? (sampledValueTemplate
?.value
?? null);
27 const sampledValueContext
= context
?? (sampledValueTemplate
?.context
?? null);
28 const sampledValueLocation
= sampledValueTemplate
?.location
?? OCPP16ServiceUtils
.getMeasurandDefaultLocation(sampledValueTemplate
?.measurand
?? null);
29 const sampledValuePhase
= phase
?? (sampledValueTemplate
?.phase
?? null);
31 ...!Utils
.isNullOrUndefined(sampledValueTemplate
.unit
) && { unit
: sampledValueTemplate
.unit
},
32 ...!Utils
.isNullOrUndefined(sampledValueContext
) && { context
: sampledValueContext
},
33 ...!Utils
.isNullOrUndefined(sampledValueTemplate
.measurand
) && { measurand
: sampledValueTemplate
.measurand
},
34 ...!Utils
.isNullOrUndefined(sampledValueLocation
) && { location
: sampledValueLocation
},
35 ...!Utils
.isNullOrUndefined(sampledValueValue
) && { value
: sampledValueValue
.toString() },
36 ...!Utils
.isNullOrUndefined(sampledValuePhase
) && { phase
: sampledValuePhase
},
40 public static getMeasurandDefaultUnit(measurandType
: OCPP16MeterValueMeasurand
): MeterValueUnit
| undefined {
41 switch (measurandType
) {
42 case OCPP16MeterValueMeasurand
.CURRENT_EXPORT
:
43 case OCPP16MeterValueMeasurand
.CURRENT_IMPORT
:
44 case OCPP16MeterValueMeasurand
.CURRENT_OFFERED
:
45 return MeterValueUnit
.AMP
;
46 case OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_EXPORT_REGISTER
:
47 case OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_IMPORT_REGISTER
:
48 return MeterValueUnit
.WATT_HOUR
;
49 case OCPP16MeterValueMeasurand
.POWER_ACTIVE_EXPORT
:
50 case OCPP16MeterValueMeasurand
.POWER_ACTIVE_IMPORT
:
51 case OCPP16MeterValueMeasurand
.POWER_OFFERED
:
52 return MeterValueUnit
.WATT
;
53 case OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
:
54 return MeterValueUnit
.PERCENT
;
55 case OCPP16MeterValueMeasurand
.VOLTAGE
:
56 return MeterValueUnit
.VOLT
;
60 public static getMeasurandDefaultLocation(measurandType
: OCPP16MeterValueMeasurand
): MeterValueLocation
| undefined {
61 switch (measurandType
) {
62 case OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
:
63 return MeterValueLocation
.EV
;
67 public static buildTransactionBeginMeterValue(chargingStation
: ChargingStation
, connectorId
: number, meterBegin
: number): OCPP16MeterValue
{
68 const meterValue
: OCPP16MeterValue
= {
69 timestamp
: new Date().toISOString(),
72 // Energy.Active.Import.Register measurand (default)
73 const sampledValueTemplate
= chargingStation
.getSampledValueTemplate(connectorId
);
74 const unitDivider
= sampledValueTemplate
?.unit
=== MeterValueUnit
.KILO_WATT_HOUR
? 1000 : 1;
75 meterValue
.sampledValue
.push(OCPP16ServiceUtils
.buildSampledValue(sampledValueTemplate
, Utils
.roundTo(meterBegin
/ unitDivider
, 4), MeterValueContext
.TRANSACTION_BEGIN
));
79 public static buildTransactionEndMeterValue(chargingStation
: ChargingStation
, connectorId
: number, meterEnd
: number): OCPP16MeterValue
{
80 const meterValue
: OCPP16MeterValue
= {
81 timestamp
: new Date().toISOString(),
84 // Energy.Active.Import.Register measurand (default)
85 const sampledValueTemplate
= chargingStation
.getSampledValueTemplate(connectorId
);
86 const unitDivider
= sampledValueTemplate
?.unit
=== MeterValueUnit
.KILO_WATT_HOUR
? 1000 : 1;
87 meterValue
.sampledValue
.push(OCPP16ServiceUtils
.buildSampledValue(sampledValueTemplate
, Utils
.roundTo(meterEnd
/ unitDivider
, 4), MeterValueContext
.TRANSACTION_END
));
91 public static buildTransactionDataMeterValues(transactionBeginMeterValue
: OCPP16MeterValue
, transactionEndMeterValue
: OCPP16MeterValue
): OCPP16MeterValue
[] {
92 const meterValues
: OCPP16MeterValue
[] = [];
93 meterValues
.push(transactionBeginMeterValue
);
94 meterValues
.push(transactionEndMeterValue
);