1 import { MeterValueContext
, MeterValueLocation
, MeterValuePhase
, MeterValueUnit
, OCPP16MeterValue
, OCPP16MeterValueMeasurand
, OCPP16SampledValue
} from
'../../../types/ocpp/1.6/MeterValues';
3 import ChargingStation from
'../../ChargingStation';
4 import Utils from
'../../../utils/Utils';
5 import logger from
'../../../utils/Logger';
7 export class OCPP16ServiceUtils
{
8 public static checkMeasurandPowerDivider(chargingStation
: ChargingStation
, measurandType
: OCPP16MeterValueMeasurand
): void {
9 if (Utils
.isUndefined(chargingStation
.stationInfo
.powerDivider
)) {
10 const errMsg
= `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
13 } else if (chargingStation
.stationInfo
?.powerDivider
<= 0) {
14 const errMsg
= `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
20 public static buildSampledValue(sampledValueTemplate
: OCPP16SampledValue
, value
: number, context
?: MeterValueContext
, phase
?: MeterValuePhase
): OCPP16SampledValue
{
21 const sampledValueContext
= context
?? (sampledValueTemplate
.context
?? null);
22 const sampledValueLocation
= sampledValueTemplate
.location
23 ? sampledValueTemplate
.location
24 : (OCPP16ServiceUtils
.getMeasurandDefaultLocation(sampledValueTemplate
.measurand
?? null));
25 const sampledValuePhase
= phase
?? (sampledValueTemplate
.phase
?? null);
27 ...!Utils
.isNullOrUndefined(sampledValueTemplate
.unit
) && { unit
: sampledValueTemplate
.unit
},
28 ...!Utils
.isNullOrUndefined(sampledValueContext
) && { context
: sampledValueContext
},
29 ...!Utils
.isNullOrUndefined(sampledValueTemplate
.measurand
) && { measurand
: sampledValueTemplate
.measurand
},
30 ...!Utils
.isNullOrUndefined(sampledValueLocation
) && { location
: sampledValueLocation
},
31 ...!Utils
.isNullOrUndefined(sampledValueTemplate
.value
) ? { value
: sampledValueTemplate
.value
} : { value
: value
.toString() },
32 ...!Utils
.isNullOrUndefined(sampledValuePhase
) && { phase
: sampledValuePhase
},
36 public static getMeasurandDefaultUnit(measurandType
: OCPP16MeterValueMeasurand
): MeterValueUnit
| undefined {
37 switch (measurandType
) {
38 case OCPP16MeterValueMeasurand
.CURRENT_EXPORT
:
39 case OCPP16MeterValueMeasurand
.CURRENT_IMPORT
:
40 case OCPP16MeterValueMeasurand
.CURRENT_OFFERED
:
41 return MeterValueUnit
.AMP
;
42 case OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_EXPORT_REGISTER
:
43 case OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_IMPORT_REGISTER
:
44 return MeterValueUnit
.WATT_HOUR
;
45 case OCPP16MeterValueMeasurand
.POWER_ACTIVE_EXPORT
:
46 case OCPP16MeterValueMeasurand
.POWER_ACTIVE_IMPORT
:
47 case OCPP16MeterValueMeasurand
.POWER_OFFERED
:
48 return MeterValueUnit
.WATT
;
49 case OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
:
50 return MeterValueUnit
.PERCENT
;
51 case OCPP16MeterValueMeasurand
.VOLTAGE
:
52 return MeterValueUnit
.VOLT
;
56 public static getMeasurandDefaultLocation(measurandType
: OCPP16MeterValueMeasurand
): MeterValueLocation
| undefined {
57 switch (measurandType
) {
58 case OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
:
59 return MeterValueLocation
.EV
;
63 public static buildTransactionBeginMeterValue(chargingStation
: ChargingStation
, connectorId
: number, meterBegin
: number): OCPP16MeterValue
{
64 const meterValue
: OCPP16MeterValue
= {
65 timestamp
: new Date().toISOString(),
68 const meterValuesTemplate
: OCPP16SampledValue
[] = chargingStation
.getConnector(connectorId
).MeterValues
;
69 for (let index
= 0; index
< meterValuesTemplate
.length
; index
++) {
70 // Energy.Active.Import.Register measurand (default)
71 if (!meterValuesTemplate
[index
].measurand
|| meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_IMPORT_REGISTER
) {
72 const unitDivider
= meterValuesTemplate
[index
]?.unit
=== MeterValueUnit
.KILO_WATT_HOUR
? 1000 : 1;
73 meterValue
.sampledValue
.push(OCPP16ServiceUtils
.buildSampledValue(meterValuesTemplate
[index
],
74 Utils
.roundTo(meterBegin
/ unitDivider
, 4), MeterValueContext
.TRANSACTION_BEGIN
));
80 public static buildTransactionEndMeterValue(chargingStation
: ChargingStation
, connectorId
: number, meterEnd
: number): OCPP16MeterValue
{
81 const meterValue
: OCPP16MeterValue
= {
82 timestamp
: new Date().toISOString(),
85 const meterValuesTemplate
: OCPP16SampledValue
[] = chargingStation
.getConnector(connectorId
).MeterValues
;
86 for (let index
= 0; index
< meterValuesTemplate
.length
; index
++) {
87 // Energy.Active.Import.Register measurand (default)
88 if (!meterValuesTemplate
[index
].measurand
|| meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_IMPORT_REGISTER
) {
89 const unitDivider
= meterValuesTemplate
[index
]?.unit
=== MeterValueUnit
.KILO_WATT_HOUR
? 1000 : 1;
90 meterValue
.sampledValue
.push(OCPP16ServiceUtils
.buildSampledValue(meterValuesTemplate
[index
], Utils
.roundTo(meterEnd
/ unitDivider
, 4), MeterValueContext
.TRANSACTION_END
));
96 public static buildTransactionDataMeterValues(transactionBeginMeterValue
: OCPP16MeterValue
, transactionEndMeterValue
: OCPP16MeterValue
): OCPP16MeterValue
[] {
97 const meterValues
: OCPP16MeterValue
[] = [];
98 meterValues
.push(transactionBeginMeterValue
);
99 meterValues
.push(transactionEndMeterValue
);