Commit | Line | Data |
---|---|---|
c0560973 JB |
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'; | |
4 | ||
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'; | |
efa43e52 | 9 | import { OCPP16BootNotificationResponse } from '../../../types/ocpp/1.6/Responses'; |
c0560973 JB |
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'; | |
18 | ||
19 | export default class OCPP16RequestService extends OCPPRequestService { | |
20 | public async sendHeartbeat(): Promise<void> { | |
21 | try { | |
22 | const payload: HeartbeatRequest = {}; | |
23 | await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.HEARTBEAT); | |
24 | } catch (error) { | |
25 | this.handleRequestError(OCPP16RequestCommand.HEARTBEAT, error); | |
26 | } | |
27 | } | |
28 | ||
29 | public async sendBootNotification(chargePointModel: string, chargePointVendor: string, chargeBoxSerialNumber?: string, firmwareVersion?: string, chargePointSerialNumber?: string, iccid?: string, imsi?: string, meterSerialNumber?: string, meterType?: string): Promise<OCPP16BootNotificationResponse> { | |
30 | try { | |
31 | const payload: OCPP16BootNotificationRequest = { | |
32 | chargePointModel, | |
33 | chargePointVendor, | |
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 } | |
41 | }; | |
42 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.BOOT_NOTIFICATION) as OCPP16BootNotificationResponse; | |
43 | } catch (error) { | |
44 | this.handleRequestError(OCPP16RequestCommand.BOOT_NOTIFICATION, error); | |
45 | } | |
46 | } | |
47 | ||
48 | public async sendStatusNotification(connectorId: number, status: OCPP16ChargePointStatus, errorCode: OCPP16ChargePointErrorCode = OCPP16ChargePointErrorCode.NO_ERROR): Promise<void> { | |
49 | try { | |
50 | const payload: StatusNotificationRequest = { | |
51 | connectorId, | |
52 | errorCode, | |
53 | status, | |
54 | }; | |
55 | await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.STATUS_NOTIFICATION); | |
56 | } catch (error) { | |
57 | this.handleRequestError(OCPP16RequestCommand.STATUS_NOTIFICATION, error); | |
58 | } | |
59 | } | |
60 | ||
61 | public async sendAuthorize(idTag?: string): Promise<OCPP16AuthorizeResponse> { | |
62 | try { | |
63 | const payload: AuthorizeRequest = { | |
64 | ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID }, | |
65 | }; | |
66 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.AUTHORIZE) as OCPP16AuthorizeResponse; | |
67 | } catch (error) { | |
68 | this.handleRequestError(OCPP16RequestCommand.AUTHORIZE, error); | |
69 | } | |
70 | } | |
71 | ||
72 | public async sendStartTransaction(connectorId: number, idTag?: string): Promise<OCPP16StartTransactionResponse> { | |
73 | try { | |
74 | const payload: StartTransactionRequest = { | |
75 | connectorId, | |
76 | ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_TAGID }, | |
77 | meterStart: 0, | |
78 | timestamp: new Date().toISOString(), | |
79 | }; | |
80 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.START_TRANSACTION) as OCPP16StartTransactionResponse; | |
81 | } catch (error) { | |
82 | this.handleRequestError(OCPP16RequestCommand.START_TRANSACTION, error); | |
83 | } | |
84 | } | |
85 | ||
86 | public async sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, reason: OCPP16StopTransactionReason = OCPP16StopTransactionReason.NONE): Promise<OCPP16StopTransactionResponse> { | |
87 | try { | |
88 | const payload: StopTransactionRequest = { | |
89 | transactionId, | |
90 | ...!Utils.isUndefined(idTag) && { idTag }, | |
91 | meterStop: meterStop, | |
92 | timestamp: new Date().toISOString(), | |
93 | ...reason && { reason }, | |
94 | }; | |
95 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.STOP_TRANSACTION) as OCPP16StartTransactionResponse; | |
96 | } catch (error) { | |
97 | this.handleRequestError(OCPP16RequestCommand.STOP_TRANSACTION, error); | |
98 | } | |
99 | } | |
100 | ||
101 | // eslint-disable-next-line consistent-this | |
102 | public async sendMeterValues(connectorId: number, transactionId: number, interval: number, self: OCPPRequestService, debug = false): Promise<void> { | |
103 | try { | |
104 | const meterValue: MeterValue = { | |
105 | timestamp: new Date().toISOString(), | |
106 | sampledValue: [], | |
107 | }; | |
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); | |
111 | // SoC measurand | |
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() }, | |
119 | }); | |
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`); | |
123 | } | |
124 | // Voltage measurand | |
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() }, | |
133 | }); | |
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()}`; | |
140 | } | |
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, | |
148 | }); | |
149 | } | |
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); | |
156 | throw 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); | |
160 | throw Error(errMsg); | |
161 | } | |
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); | |
175 | } | |
176 | powerMeasurandValues.allPhases = Utils.roundTo(powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, 2); | |
177 | } | |
178 | break; | |
179 | case PowerOutType.DC: | |
180 | if (Utils.isUndefined(meterValuesTemplate[index].value)) { | |
181 | powerMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxPower); | |
182 | } | |
183 | break; | |
184 | default: | |
185 | logger.error(errMsg); | |
186 | throw Error(errMsg); | |
187 | } | |
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() }, | |
194 | }); | |
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}`); | |
198 | } | |
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, | |
208 | }); | |
209 | } | |
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); | |
216 | throw 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); | |
220 | throw Error(errMsg); | |
221 | } | |
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); | |
235 | } | |
236 | currentMeasurandValues.allPhases = Utils.roundTo((currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / self.chargingStation.getNumberOfPhases(), 2); | |
237 | } | |
238 | break; | |
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); | |
243 | } | |
244 | break; | |
245 | default: | |
246 | logger.error(errMsg); | |
247 | throw Error(errMsg); | |
248 | } | |
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() }, | |
255 | }); | |
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}`); | |
259 | } | |
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, | |
269 | }); | |
270 | } | |
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); | |
277 | throw 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); | |
281 | throw Error(errMsg); | |
282 | } | |
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; | |
288 | } else { | |
289 | connector.lastEnergyActiveImportRegisterValue = 0; | |
290 | } | |
291 | } | |
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() }, | |
299 | }); | |
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}`); | |
304 | } | |
305 | // Unsupported measurand | |
306 | } else { | |
307 | logger.info(`${self.chargingStation.logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} on connectorId ${connectorId}`); | |
308 | } | |
309 | } | |
310 | const payload: MeterValuesRequest = { | |
311 | connectorId, | |
312 | transactionId, | |
313 | meterValue, | |
314 | }; | |
315 | await self.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.METERVALUES); | |
316 | } catch (error) { | |
317 | self.handleRequestError(OCPP16RequestCommand.METERVALUES, error); | |
318 | } | |
319 | } | |
320 | ||
321 | public async sendError(messageId: string, error: OCPPError, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise<unknown> { | |
322 | // Send error | |
323 | return this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName); | |
324 | } | |
325 | } |