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 { ACElectricUtils
} from
'../../../utils/ElectricUtils';
6 import Constants from
'../../../utils/Constants';
7 import { CurrentOutType
} from
'../../../types/ChargingStationTemplate';
8 import MeasurandValues from
'../../../types/MeasurandValues';
9 import { MessageType
} from
'../../../types/ocpp/MessageType';
10 import { OCPP16BootNotificationResponse
} from
'../../../types/ocpp/1.6/Responses';
11 import { OCPP16ChargePointErrorCode
} from
'../../../types/ocpp/1.6/ChargePointErrorCode';
12 import { OCPP16ChargePointStatus
} from
'../../../types/ocpp/1.6/ChargePointStatus';
13 import { OCPP16StandardParametersKey
} from
'../../../types/ocpp/1.6/Configuration';
14 import OCPPError from
'../../OcppError';
15 import OCPPRequestService from
'../OCPPRequestService';
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
,
49 errorCode
: OCPP16ChargePointErrorCode
= OCPP16ChargePointErrorCode
.NO_ERROR
): Promise
<void> {
51 const payload
: StatusNotificationRequest
= {
56 await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.STATUS_NOTIFICATION
);
58 this.handleRequestError(OCPP16RequestCommand
.STATUS_NOTIFICATION
, error
);
62 public async sendAuthorize(idTag
?: string): Promise
<OCPP16AuthorizeResponse
> {
64 const payload
: AuthorizeRequest
= {
65 ...!Utils
.isUndefined(idTag
) ? { idTag
} : { idTag
: Constants
.TRANSACTION_DEFAULT_TAGID
},
67 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.AUTHORIZE
) as OCPP16AuthorizeResponse
;
69 this.handleRequestError(OCPP16RequestCommand
.AUTHORIZE
, error
);
73 public async sendStartTransaction(connectorId
: number, idTag
?: string): Promise
<OCPP16StartTransactionResponse
> {
75 const payload
: StartTransactionRequest
= {
77 ...!Utils
.isUndefined(idTag
) ? { idTag
} : { idTag
: Constants
.TRANSACTION_DEFAULT_TAGID
},
79 timestamp
: new Date().toISOString(),
81 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.START_TRANSACTION
) as OCPP16StartTransactionResponse
;
83 this.handleRequestError(OCPP16RequestCommand
.START_TRANSACTION
, error
);
87 public async sendStopTransaction(transactionId
: number, meterStop
: number, idTag
?: string,
88 reason
: OCPP16StopTransactionReason
= OCPP16StopTransactionReason
.NONE
): Promise
<OCPP16StopTransactionResponse
> {
90 const payload
: StopTransactionRequest
= {
92 ...!Utils
.isUndefined(idTag
) && { idTag
},
94 timestamp
: new Date().toISOString(),
95 ...reason
&& { reason
},
97 return await this.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.STOP_TRANSACTION
) as OCPP16StartTransactionResponse
;
99 this.handleRequestError(OCPP16RequestCommand
.STOP_TRANSACTION
, error
);
103 // eslint-disable-next-line consistent-this
104 public async sendMeterValues(connectorId
: number, transactionId
: number, interval
: number, self: OCPPRequestService
, debug
= false): Promise
<void> {
106 const meterValue
: MeterValue
= {
107 timestamp
: new Date().toISOString(),
110 const meterValuesTemplate
: OCPP16SampledValue
[] = self.chargingStation
.getConnector(connectorId
).MeterValues
;
111 for (let index
= 0; index
< meterValuesTemplate
.length
; index
++) {
112 const connector
= self.chargingStation
.getConnector(connectorId
);
114 if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.STATE_OF_CHARGE
)) {
115 meterValue
.sampledValue
.push({
116 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.PERCENT
},
117 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
118 measurand
: meterValuesTemplate
[index
].measurand
,
119 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) ? { location
: meterValuesTemplate
[index
].location
} : { location
: MeterValueLocation
.EV
},
120 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: Utils
.getRandomInt(100).toString() },
122 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
123 if (Utils
.convertToInt(meterValue
.sampledValue
[sampledValuesIndex
].value
) > 100 || debug
) {
124 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`);
127 } else if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.VOLTAGE
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.VOLTAGE
)) {
128 const voltageMeasurandValue
= Utils
.getRandomFloatRounded(self.chargingStation
.getVoltageOut() + self.chargingStation
.getVoltageOut() * 0.1, self.chargingStation
.getVoltageOut() - self.chargingStation
.getVoltageOut() * 0.1);
129 meterValue
.sampledValue
.push({
130 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.VOLT
},
131 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
132 measurand
: meterValuesTemplate
[index
].measurand
,
133 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
134 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: voltageMeasurandValue
.toString() },
136 for (let phase
= 1; self.chargingStation
.getNumberOfPhases() === 3 && phase
<= self.chargingStation
.getNumberOfPhases(); phase
++) {
137 let phaseValue
: string;
138 if (self.chargingStation
.getVoltageOut() >= 0 && self.chargingStation
.getVoltageOut() <= 250) {
139 phaseValue
= `L${phase}-N`;
140 } else if (self.chargingStation
.getVoltageOut() > 250) {
141 phaseValue
= `L${phase}-L${(phase + 1) % self.chargingStation.getNumberOfPhases() !== 0 ? (phase + 1) % self.chargingStation.getNumberOfPhases() : self.chargingStation.getNumberOfPhases()}`;
143 meterValue
.sampledValue
.push({
144 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.VOLT
},
145 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
146 measurand
: meterValuesTemplate
[index
].measurand
,
147 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
148 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: voltageMeasurandValue
.toString() },
149 phase
: phaseValue
as MeterValuePhase
,
152 // Power.Active.Import measurand
153 } else if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.POWER_ACTIVE_IMPORT
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.POWER_ACTIVE_IMPORT
)) {
154 // FIXME: factor out powerDivider checks
155 if (Utils
.isUndefined(self.chargingStation
.stationInfo
.powerDivider
)) {
156 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
157 logger
.error(errMsg
);
159 } else if (self.chargingStation
.stationInfo
.powerDivider
&& self.chargingStation
.stationInfo
.powerDivider
<= 0) {
160 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}`;
161 logger
.error(errMsg
);
164 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
165 const powerMeasurandValues
= {} as MeasurandValues
;
166 const maxPower
= Math.round(self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
);
167 const maxPowerPerPhase
= Math.round((self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
) / self.chargingStation
.getNumberOfPhases());
168 switch (self.chargingStation
.getCurrentOutType()) {
169 case CurrentOutType
.AC
:
170 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
171 powerMeasurandValues
.L1
= Utils
.getRandomFloatRounded(maxPowerPerPhase
);
172 powerMeasurandValues
.L2
= 0;
173 powerMeasurandValues
.L3
= 0;
174 if (self.chargingStation
.getNumberOfPhases() === 3) {
175 powerMeasurandValues
.L2
= Utils
.getRandomFloatRounded(maxPowerPerPhase
);
176 powerMeasurandValues
.L3
= Utils
.getRandomFloatRounded(maxPowerPerPhase
);
178 powerMeasurandValues
.allPhases
= Utils
.roundTo(powerMeasurandValues
.L1
+ powerMeasurandValues
.L2
+ powerMeasurandValues
.L3
, 2);
181 case CurrentOutType
.DC
:
182 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
183 powerMeasurandValues
.allPhases
= Utils
.getRandomFloatRounded(maxPower
);
187 logger
.error(errMsg
);
190 meterValue
.sampledValue
.push({
191 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.WATT
},
192 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
193 measurand
: meterValuesTemplate
[index
].measurand
,
194 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
195 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: powerMeasurandValues
.allPhases
.toString() },
197 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
198 if (Utils
.convertToFloat(meterValue
.sampledValue
[sampledValuesIndex
].value
) > maxPower
|| debug
) {
199 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}`);
201 for (let phase
= 1; self.chargingStation
.getNumberOfPhases() === 3 && phase
<= self.chargingStation
.getNumberOfPhases(); phase
++) {
202 const phaseValue
= `L${phase}-N`;
203 meterValue
.sampledValue
.push({
204 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.WATT
},
205 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
206 ...!Utils
.isUndefined(meterValuesTemplate
[index
].measurand
) && { measurand
: meterValuesTemplate
[index
].measurand
},
207 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
208 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: powerMeasurandValues
[`L${phase}`] as string },
209 phase
: phaseValue
as MeterValuePhase
,
212 // Current.Import measurand
213 } else if (meterValuesTemplate
[index
].measurand
&& meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.CURRENT_IMPORT
&& self.chargingStation
.getConfigurationKey(OCPP16StandardParametersKey
.MeterValuesSampledData
).value
.includes(OCPP16MeterValueMeasurand
.CURRENT_IMPORT
)) {
214 // FIXME: factor out powerDivider checks
215 if (Utils
.isUndefined(self.chargingStation
.stationInfo
.powerDivider
)) {
216 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
217 logger
.error(errMsg
);
219 } else if (self.chargingStation
.stationInfo
.powerDivider
&& self.chargingStation
.stationInfo
.powerDivider
<= 0) {
220 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}`;
221 logger
.error(errMsg
);
224 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
225 const currentMeasurandValues
: MeasurandValues
= {} as MeasurandValues
;
226 let maxAmperage
: number;
227 switch (self.chargingStation
.getCurrentOutType()) {
228 case CurrentOutType
.AC
:
229 maxAmperage
= ACElectricUtils
.amperagePerPhaseFromPower(self.chargingStation
.getNumberOfPhases(), self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
, self.chargingStation
.getVoltageOut());
230 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
231 currentMeasurandValues
.L1
= Utils
.getRandomFloatRounded(maxAmperage
);
232 currentMeasurandValues
.L2
= 0;
233 currentMeasurandValues
.L3
= 0;
234 if (self.chargingStation
.getNumberOfPhases() === 3) {
235 currentMeasurandValues
.L2
= Utils
.getRandomFloatRounded(maxAmperage
);
236 currentMeasurandValues
.L3
= Utils
.getRandomFloatRounded(maxAmperage
);
238 currentMeasurandValues
.allPhases
= Utils
.roundTo((currentMeasurandValues
.L1
+ currentMeasurandValues
.L2
+ currentMeasurandValues
.L3
) / self.chargingStation
.getNumberOfPhases(), 2);
241 case CurrentOutType
.DC
:
242 maxAmperage
= ACElectricUtils
.amperageTotalFromPower(self.chargingStation
.stationInfo
.maxPower
/ self.chargingStation
.stationInfo
.powerDivider
, self.chargingStation
.getVoltageOut());
243 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
244 currentMeasurandValues
.allPhases
= Utils
.getRandomFloatRounded(maxAmperage
);
248 logger
.error(errMsg
);
251 meterValue
.sampledValue
.push({
252 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.AMP
},
253 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
254 measurand
: meterValuesTemplate
[index
].measurand
,
255 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
256 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: currentMeasurandValues
.allPhases
.toString() },
258 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
259 if (Utils
.convertToFloat(meterValue
.sampledValue
[sampledValuesIndex
].value
) > maxAmperage
|| debug
) {
260 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}`);
262 for (let phase
= 1; self.chargingStation
.getNumberOfPhases() === 3 && phase
<= self.chargingStation
.getNumberOfPhases(); phase
++) {
263 const phaseValue
= `L${phase}`;
264 meterValue
.sampledValue
.push({
265 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.AMP
},
266 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
267 ...!Utils
.isUndefined(meterValuesTemplate
[index
].measurand
) && { measurand
: meterValuesTemplate
[index
].measurand
},
268 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
269 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} : { value
: currentMeasurandValues
[phaseValue
] as string },
270 phase
: phaseValue
as MeterValuePhase
,
273 // Energy.Active.Import.Register measurand (default)
274 } else if (!meterValuesTemplate
[index
].measurand
|| meterValuesTemplate
[index
].measurand
=== OCPP16MeterValueMeasurand
.ENERGY_ACTIVE_IMPORT_REGISTER
) {
275 // FIXME: factor out powerDivider checks
276 if (Utils
.isUndefined(self.chargingStation
.stationInfo
.powerDivider
)) {
277 const errMsg
= `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
278 logger
.error(errMsg
);
280 } else if (self.chargingStation
.stationInfo
.powerDivider
&& self.chargingStation
.stationInfo
.powerDivider
<= 0) {
281 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}`;
282 logger
.error(errMsg
);
285 if (Utils
.isUndefined(meterValuesTemplate
[index
].value
)) {
286 const measurandValue
= Utils
.getRandomInt(self.chargingStation
.stationInfo
.maxPower
/ (self.chargingStation
.stationInfo
.powerDivider
* 3600000) * interval
);
287 // Persist previous value in connector
288 if (connector
&& !Utils
.isNullOrUndefined(connector
.lastEnergyActiveImportRegisterValue
) && connector
.lastEnergyActiveImportRegisterValue
>= 0) {
289 connector
.lastEnergyActiveImportRegisterValue
+= measurandValue
;
291 connector
.lastEnergyActiveImportRegisterValue
= 0;
294 meterValue
.sampledValue
.push({
295 ...!Utils
.isUndefined(meterValuesTemplate
[index
].unit
) ? { unit
: meterValuesTemplate
[index
].unit
} : { unit
: MeterValueUnit
.WATT_HOUR
},
296 ...!Utils
.isUndefined(meterValuesTemplate
[index
].context
) && { context
: meterValuesTemplate
[index
].context
},
297 ...!Utils
.isUndefined(meterValuesTemplate
[index
].measurand
) && { measurand
: meterValuesTemplate
[index
].measurand
},
298 ...!Utils
.isUndefined(meterValuesTemplate
[index
].location
) && { location
: meterValuesTemplate
[index
].location
},
299 ...!Utils
.isUndefined(meterValuesTemplate
[index
].value
) ? { value
: meterValuesTemplate
[index
].value
} :
300 { value
: connector
.lastEnergyActiveImportRegisterValue
.toString() },
302 const sampledValuesIndex
= meterValue
.sampledValue
.length
- 1;
303 const maxConsumption
= Math.round(self.chargingStation
.stationInfo
.maxPower
* 3600 / (self.chargingStation
.stationInfo
.powerDivider
* interval
));
304 if (Utils
.convertToFloat(meterValue
.sampledValue
[sampledValuesIndex
].value
) > maxConsumption
|| debug
) {
305 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}`);
307 // Unsupported measurand
309 logger
.info(`${self.chargingStation.logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} on connectorId ${connectorId}`);
312 const payload
: MeterValuesRequest
= {
317 await self.sendMessage(Utils
.generateUUID(), payload
, MessageType
.CALL_MESSAGE
, OCPP16RequestCommand
.METER_VALUES
);
319 self.handleRequestError(OCPP16RequestCommand
.METER_VALUES
, error
);
323 public async sendError(messageId
: string, error
: OCPPError
, commandName
: OCPP16RequestCommand
| OCPP16IncomingRequestCommand
): Promise
<unknown
> {
325 return this.sendMessage(messageId
, error
, MessageType
.CALL_ERROR_MESSAGE
, commandName
);