1 import { AuthorizeRequest
, OCPP16AuthorizeResponse
, OCPP16StartTransactionResponse
, OCPP16StopTransactionReason
, OCPP16StopTransactionResponse
, StartTransactionRequest
, StopTransactionRequest
} from
'../../../types/ocpp/1.6/Transaction';
2 import { HeartbeatRequest
, OCPP16BootNotificationRequest
, OCPP16IncomingRequestCommand
, OCPP16RequestCommand
, StatusNotificationRequest
} from
'../../../types/ocpp/1.6/Requests';
3 import { MeterValue
, MeterValueLocation
, MeterValuePhase
, MeterValueUnit
, MeterValuesRequest
, OCPP16MeterValueMeasurand
, OCPP16SampledValue
} from
'../../../types/ocpp/1.6/MeterValues';
5 import Constants from
'../../../utils/Constants';
6 import ElectricUtils from
'../../../utils/ElectricUtils';
7 import MeasurandValues from
'../../../types/MeasurandValues';
8 import { MessageType
} from
'../../../types/ocpp/MessageType';
9 import { OCPP16BootNotificationResponse
} from
'../../../types/ocpp/1.6/Responses';
10 import { OCPP16ChargePointErrorCode
} from
'../../../types/ocpp/1.6/ChargePointErrorCode';
11 import { OCPP16ChargePointStatus
} from
'../../../types/ocpp/1.6/ChargePointStatus';
12 import { OCPP16StandardParametersKey
} from
'../../../types/ocpp/1.6/Configuration';
13 import OCPPError from
'../../OcppError';
14 import OCPPRequestService from
'../OCPPRequestService';
15 import { PowerOutType
} from
'../../../types/ChargingStationTemplate';
16 import Utils from
'../../../utils/Utils';
17 import logger from
'../../../utils/Logger';
19 export default class OCPP16RequestService
extends OCPPRequestService
{
20 public async sendHeartbeat(): Promise
<void> {
22 const payload
: HeartbeatRequest
= {};
23 await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.HEARTBEAT
);
25 this.handleRequestError(OCPP16RequestCommand
.HEARTBEAT
, error
);
29 public async sendBootNotification(chargePointModel
: string, chargePointVendor
: string, chargeBoxSerialNumber
?: string, firmwareVersion
?: string, chargePointSerialNumber
?: string, iccid
?: string, imsi
?: string, meterSerialNumber
?: string, meterType
?: string): Promise
<OCPP16BootNotificationResponse
> {
31 const payload
: OCPP16BootNotificationRequest
= {
34 ...!Utils
.isUndefined(chargeBoxSerialNumber
) && { chargeBoxSerialNumber
},
35 ...!Utils
.isUndefined(chargePointSerialNumber
) && { chargePointSerialNumber
},
36 ...!Utils
.isUndefined(firmwareVersion
) && { firmwareVersion
},
37 ...!Utils
.isUndefined(iccid
) && { iccid
},
38 ...!Utils
.isUndefined(imsi
) && { imsi
},
39 ...!Utils
.isUndefined(meterSerialNumber
) && { meterSerialNumber
},
40 ...!Utils
.isUndefined(meterType
) && { meterType
}
42 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.BOOT_NOTIFICATION
) as OCPP16BootNotificationResponse
;
44 this.handleRequestError(OCPP16RequestCommand
.BOOT_NOTIFICATION
, error
);
48 public async sendStatusNotification(connectorId
: number, status: OCPP16ChargePointStatus
, errorCode
: OCPP16ChargePointErrorCode
= OCPP16ChargePointErrorCode
.NO_ERROR
): Promise
<void> {
50 const payload
: StatusNotificationRequest
= {
55 await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.STATUS_NOTIFICATION
);
57 this.handleRequestError(OCPP16RequestCommand
.STATUS_NOTIFICATION
, error
);
61 public async sendAuthorize(idTag
?: string): Promise
<OCPP16AuthorizeResponse
> {
63 const payload
: AuthorizeRequest
= {
64 ...!Utils
.isUndefined(idTag
) ? { idTag
} : { idTag
: Constants
.TRANSACTION_DEFAULT_TAGID
},
66 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.AUTHORIZE
) as OCPP16AuthorizeResponse
;
68 this.handleRequestError(OCPP16RequestCommand
.AUTHORIZE
, error
);
72 public async sendStartTransaction(connectorId
: number, idTag
?: string): Promise
<OCPP16StartTransactionResponse
> {
74 const payload
: StartTransactionRequest
= {
76 ...!Utils
.isUndefined(idTag
) ? { idTag
} : { idTag
: Constants
.TRANSACTION_DEFAULT_TAGID
},
78 timestamp
: new Date().toISOString(),
80 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.START_TRANSACTION
) as OCPP16StartTransactionResponse
;
82 this.handleRequestError(OCPP16RequestCommand
.START_TRANSACTION
, error
);
86 public async sendStopTransaction(transactionId
: number, meterStop
: number, idTag
?: string, reason
: OCPP16StopTransactionReason
= OCPP16StopTransactionReason
.NONE
): Promise
<OCPP16StopTransactionResponse
> {
88 const payload
: StopTransactionRequest
= {
90 ...!Utils
.isUndefined(idTag
) && { idTag
},
92 timestamp
: new Date().toISOString(),
93 ...reason
&& { reason
},
95 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.STOP_TRANSACTION
) as OCPP16StartTransactionResponse
;
97 this.handleRequestError(OCPP16RequestCommand
.STOP_TRANSACTION
, error
);
101 // eslint-disable-next-line consistent-this
102 public async sendMeterValues(connectorId
: number, transactionId
: number, interval
: number, self: OCPPRequestService
, debug
= false): Promise
<void> {
104 const meterValue
: MeterValue
= {
105 timestamp
: new Date().toISOString(),
108 const meterValuesTemplate
: OCPP16SampledValue
[] = self.chargingStation
.getConnector(connectorId
).MeterValues
;
109 for (let index
= 0; index
< meterValuesTemplate
.length
; index
++) {
110 const connector
= self.chargingStation
.getConnector(connectorId
);
112 if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
)) {
113 meterValue
.sampledValue
.push({
114 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.PERCENT
},
115 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
116 measurand
: meterValuesTemplate
[index
].measurand
,
117 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) ? { location
: meterValuesTemplate
[index
].location
} : { location
: MeterValueLocation
.EV
},
118 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: Utils
.getRandomInt(100).toString() },
120 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
121 if (Utils
.convertToInt(meterValue
.sampledValue
[sampledValuesIndex
].value
) > 100 || debug
) {
122 logger
.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/100`);
125 } else if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.VOLTAGE
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.VOLTAGE
)) {
126 const voltageMeasurandValue
= Utils
.getRandomFloatRounded(self.chargingStation
.getVoltageOut() + self.chargingStation
.getVoltageOut() * 0.1, self.chargingStation
.getVoltageOut() - self.chargingStation
.getVoltageOut() * 0.1);
127 meterValue
.sampledValue
.push({
128 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.VOLT
},
129 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
130 measurand
: meterValuesTemplate
[index
].measurand
,
131 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
132 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: voltageMeasurandValue
.toString() },
134 for (let phase
= 1; self.chargingStation
.getNumberOfPhases() === 3 && phase
<= self.chargingStation
.getNumberOfPhases(); phase
++) {
135 let phaseValue
: string;
136 if (self.chargingStation
.getVoltageOut() >= 0 && self.chargingStation
.getVoltageOut() <= 250) {
137 phaseValue
= `L${phase}-N`;
138 } else if (self.chargingStation
.getVoltageOut() > 250) {
139 phaseValue
= `L${phase}-L${(phase + 1) % self.chargingStation.getNumberOfPhases() !== 0 ? (phase + 1) % self.chargingStation.getNumberOfPhases() : self.chargingStation.getNumberOfPhases()}`;
141 meterValue
.sampledValue
.push({
142 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.VOLT
},
143 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
144 measurand
: meterValuesTemplate
[index
].measurand
,
145 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
146 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: voltageMeasurandValue
.toString() },
147 phase
: phaseValue
as MeterValuePhase
,
150 // Power.Active.Import measurand
151 } else if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.POWER_ACTIVE_IMPORT
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.POWER_ACTIVE_IMPORT
)) {
152 // FIXME: factor out powerDivider checks
153 if (Utils
.isUndefined(self.chargingStation
.stationInfo
.powerDivider
)) {
154 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
155 logger
.error(errMsg
);
157 } else if (self.chargingStation
.stationInfo
.powerDivider
&& self.chargingStation
.stationInfo
.powerDivider
<= 0) {
158 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${self.chargingStation.stationInfo.powerDivider}`;
159 logger
.error(errMsg
);
162 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getPowerOutType()} powerOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
163 const powerMeasurandValues
= {} as MeasurandValues
;
164 const maxPower
= Math.round(self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
);
165 const maxPowerPerPhase
= Math.round((self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
) / self.chargingStation
.getNumberOfPhases());
166 switch (self.chargingStation
.getPowerOutType()) {
167 case PowerOutType
.AC
:
168 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
169 powerMeasurandValues
.L1
= Utils
.getRandomFloatRounded(maxPowerPerPhase
);
170 powerMeasurandValues
.L2
= 0;
171 powerMeasurandValues
.L3
= 0;
172 if (self.chargingStation
.getNumberOfPhases() === 3) {
173 powerMeasurandValues
.L2
= Utils
.getRandomFloatRounded(maxPowerPerPhase
);
174 powerMeasurandValues
.L3
= Utils
.getRandomFloatRounded(maxPowerPerPhase
);
176 powerMeasurandValues
.allPhases
= Utils
.roundTo(powerMeasurandValues
.L1
+ powerMeasurandValues
.L2
+ powerMeasurandValues
.L3
, 2);
179 case PowerOutType
.DC
:
180 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
181 powerMeasurandValues
.allPhases
= Utils
.getRandomFloatRounded(maxPower
);
185 logger
.error(errMsg
);
188 meterValue
.sampledValue
.push({
189 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.WATT
},
190 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
191 measurand
: meterValuesTemplate
[index
].measurand
,
192 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
193 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: powerMeasurandValues
.allPhases
.toString() },
195 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
196 if (Utils
.convertToFloat(meterValue
.sampledValue
[sampledValuesIndex
].value
) > maxPower
|| debug
) {
197 logger
.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPower}`);
199 for (let phase
= 1; self.chargingStation
.getNumberOfPhases() === 3 && phase
<= self.chargingStation
.getNumberOfPhases(); phase
++) {
200 const phaseValue
= `L${phase}-N`;
201 meterValue
.sampledValue
.push({
202 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.WATT
},
203 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
204 ...!Utils
.isUndefined(meterValuesTemplate
[index
].measurand
) && { measurand
: meterValuesTemplate
[index
].measurand
},
205 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
206 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: powerMeasurandValues
[`L${phase}`] as string },
207 phase
: phaseValue
as MeterValuePhase
,
210 // Current.Import measurand
211 } else if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.CURRENT_IMPORT
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.CURRENT_IMPORT
)) {
212 // FIXME: factor out powerDivider checks
213 if (Utils
.isUndefined(self.chargingStation
.stationInfo
.powerDivider
)) {
214 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
215 logger
.error(errMsg
);
217 } else if (self.chargingStation
.stationInfo
.powerDivider
&& self.chargingStation
.stationInfo
.powerDivider
<= 0) {
218 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${self.chargingStation.stationInfo.powerDivider}`;
219 logger
.error(errMsg
);
222 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getPowerOutType()} powerOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
223 const currentMeasurandValues
: MeasurandValues
= {} as MeasurandValues
;
224 let maxAmperage
: number;
225 switch (self.chargingStation
.getPowerOutType()) {
226 case PowerOutType
.AC
:
227 maxAmperage
= ElectricUtils
.ampPerPhaseFromPower(self.chargingStation
.getNumberOfPhases(), self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
, self.chargingStation
.getVoltageOut());
228 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
229 currentMeasurandValues
.L1
= Utils
.getRandomFloatRounded(maxAmperage
);
230 currentMeasurandValues
.L2
= 0;
231 currentMeasurandValues
.L3
= 0;
232 if (self.chargingStation
.getNumberOfPhases() === 3) {
233 currentMeasurandValues
.L2
= Utils
.getRandomFloatRounded(maxAmperage
);
234 currentMeasurandValues
.L3
= Utils
.getRandomFloatRounded(maxAmperage
);
236 currentMeasurandValues
.allPhases
= Utils
.roundTo((currentMeasurandValues
.L1
+ currentMeasurandValues
.L2
+ currentMeasurandValues
.L3
) / self.chargingStation
.getNumberOfPhases(), 2);
239 case PowerOutType
.DC
:
240 maxAmperage
= ElectricUtils
.ampTotalFromPower(self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
, self.chargingStation
.getVoltageOut());
241 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
242 currentMeasurandValues
.allPhases
= Utils
.getRandomFloatRounded(maxAmperage
);
246 logger
.error(errMsg
);
249 meterValue
.sampledValue
.push({
250 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.AMP
},
251 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
252 measurand
: meterValuesTemplate
[index
].measurand
,
253 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
254 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: currentMeasurandValues
.allPhases
.toString() },
256 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
257 if (Utils
.convertToFloat(meterValue
.sampledValue
[sampledValuesIndex
].value
) > maxAmperage
|| debug
) {
258 logger
.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxAmperage}`);
260 for (let phase
= 1; self.chargingStation
.getNumberOfPhases() === 3 && phase
<= self.chargingStation
.getNumberOfPhases(); phase
++) {
261 const phaseValue
= `L${phase}`;
262 meterValue
.sampledValue
.push({
263 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.AMP
},
264 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
265 ...!Utils
.isUndefined(meterValuesTemplate
[index
].measurand
) && { measurand
: meterValuesTemplate
[index
].measurand
},
266 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
267 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: currentMeasurandValues
[phaseValue
] as string },
268 phase
: phaseValue
as MeterValuePhase
,
271 // Energy.Active.Import.Register measurand (default)
272 } else if (!meterValuesTemplate
[index
].measurand
|| meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_IMPORT_REGISTER
) {
273 // FIXME: factor out powerDivider checks
274 if (Utils
.isUndefined(self.chargingStation
.stationInfo
.powerDivider
)) {
275 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
276 logger
.error(errMsg
);
278 } else if (self.chargingStation
.stationInfo
.powerDivider
&& self.chargingStation
.stationInfo
.powerDivider
<= 0) {
279 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${self.chargingStation.stationInfo.powerDivider}`;
280 logger
.error(errMsg
);
283 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
284 const measurandValue
= Utils
.getRandomInt(self.chargingStation
.stationInfo
.maxPower
/ (self.chargingStation
.stationInfo
.powerDivider
* 3600000) * interval
);
285 // Persist previous value in connector
286 if (connector
&& !Utils
.isNullOrUndefined(connector
.lastEnergyActiveImportRegisterValue
) && connector
.lastEnergyActiveImportRegisterValue
>= 0) {
287 connector
.lastEnergyActiveImportRegisterValue
+= measurandValue
;
289 connector
.lastEnergyActiveImportRegisterValue
= 0;
292 meterValue
.sampledValue
.push({
293 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.WATT_HOUR
},
294 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
295 ...!Utils
.isUndefined(meterValuesTemplate
[index
].measurand
) && { measurand
: meterValuesTemplate
[index
].measurand
},
296 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
297 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} :
298 { value
: connector
.lastEnergyActiveImportRegisterValue
.toString() },
300 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
301 const maxConsumption
= Math.round(self.chargingStation
.stationInfo
.maxPower
* 3600 / (self.chargingStation
.stationInfo
.powerDivider
* interval
));
302 if (Utils
.convertToFloat(meterValue
.sampledValue
[sampledValuesIndex
].value
) > maxConsumption
|| debug
) {
303 logger
.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ? meterValue.sampledValue[sampledValuesIndex].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxConsumption}`);
305 // Unsupported measurand
307 logger
.info(`${self.chargingStation.logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} on connectorId ${connectorId}`);
310 const payload
: MeterValuesRequest
= {
315 await self.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.METERVALUES
);
317 self.handleRequestError(OCPP16RequestCommand
.METERVALUES
, error
);
321 public async sendError(messageId
: string, error
: OCPPError
, commandName
: OCPP16RequestCommand
| OCPP16IncomingRequestCommand
): Promise
<unknown
> {
323 return this.sendMessage(messageId
, error
, MessageType
.CALL_ERROR_MESSAGE
, commandName
);