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 | ||
cb31c873 | 5 | import { ACElectricUtils } from '../../../utils/ElectricUtils'; |
c0560973 | 6 | import Constants from '../../../utils/Constants'; |
7decf1b6 | 7 | import { CurrentOutType } from '../../../types/ChargingStationTemplate'; |
c0560973 JB |
8 | import MeasurandValues from '../../../types/MeasurandValues'; |
9 | import { MessageType } from '../../../types/ocpp/MessageType'; | |
efa43e52 | 10 | import { OCPP16BootNotificationResponse } from '../../../types/ocpp/1.6/Responses'; |
c0560973 JB |
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'; | |
c0560973 JB |
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 | ||
035742f7 JB |
48 | public async sendStatusNotification(connectorId: number, status: OCPP16ChargePointStatus, |
49 | errorCode: OCPP16ChargePointErrorCode = OCPP16ChargePointErrorCode.NO_ERROR): Promise<void> { | |
c0560973 JB |
50 | try { |
51 | const payload: StatusNotificationRequest = { | |
52 | connectorId, | |
53 | errorCode, | |
54 | status, | |
55 | }; | |
56 | await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.STATUS_NOTIFICATION); | |
57 | } catch (error) { | |
58 | this.handleRequestError(OCPP16RequestCommand.STATUS_NOTIFICATION, error); | |
59 | } | |
60 | } | |
61 | ||
62 | public async sendAuthorize(idTag?: string): Promise<OCPP16AuthorizeResponse> { | |
63 | try { | |
64 | const payload: AuthorizeRequest = { | |
bb3343f9 | 65 | ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG }, |
c0560973 JB |
66 | }; |
67 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.AUTHORIZE) as OCPP16AuthorizeResponse; | |
68 | } catch (error) { | |
69 | this.handleRequestError(OCPP16RequestCommand.AUTHORIZE, error); | |
70 | } | |
71 | } | |
72 | ||
73 | public async sendStartTransaction(connectorId: number, idTag?: string): Promise<OCPP16StartTransactionResponse> { | |
74 | try { | |
75 | const payload: StartTransactionRequest = { | |
76 | connectorId, | |
bb3343f9 | 77 | ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.TRANSACTION_DEFAULT_IDTAG }, |
c0560973 JB |
78 | meterStart: 0, |
79 | timestamp: new Date().toISOString(), | |
80 | }; | |
81 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.START_TRANSACTION) as OCPP16StartTransactionResponse; | |
82 | } catch (error) { | |
83 | this.handleRequestError(OCPP16RequestCommand.START_TRANSACTION, error); | |
84 | } | |
85 | } | |
86 | ||
035742f7 JB |
87 | public async sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, |
88 | reason: OCPP16StopTransactionReason = OCPP16StopTransactionReason.NONE): Promise<OCPP16StopTransactionResponse> { | |
c0560973 JB |
89 | try { |
90 | const payload: StopTransactionRequest = { | |
91 | transactionId, | |
92 | ...!Utils.isUndefined(idTag) && { idTag }, | |
93 | meterStop: meterStop, | |
94 | timestamp: new Date().toISOString(), | |
95 | ...reason && { reason }, | |
96 | }; | |
97 | return await this.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.STOP_TRANSACTION) as OCPP16StartTransactionResponse; | |
98 | } catch (error) { | |
99 | this.handleRequestError(OCPP16RequestCommand.STOP_TRANSACTION, error); | |
100 | } | |
101 | } | |
102 | ||
103 | // eslint-disable-next-line consistent-this | |
104 | public async sendMeterValues(connectorId: number, transactionId: number, interval: number, self: OCPPRequestService, debug = false): Promise<void> { | |
105 | try { | |
106 | const meterValue: MeterValue = { | |
107 | timestamp: new Date().toISOString(), | |
108 | sampledValue: [], | |
109 | }; | |
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); | |
113 | // SoC measurand | |
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() }, | |
121 | }); | |
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`); | |
125 | } | |
126 | // Voltage measurand | |
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() }, | |
135 | }); | |
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()}`; | |
142 | } | |
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, | |
150 | }); | |
151 | } | |
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); | |
158 | throw 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); | |
162 | throw Error(errMsg); | |
163 | } | |
7decf1b6 | 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`; |
c0560973 JB |
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()); | |
7decf1b6 JB |
168 | switch (self.chargingStation.getCurrentOutType()) { |
169 | case CurrentOutType.AC: | |
c0560973 JB |
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); | |
177 | } | |
178 | powerMeasurandValues.allPhases = Utils.roundTo(powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, 2); | |
179 | } | |
180 | break; | |
7decf1b6 | 181 | case CurrentOutType.DC: |
c0560973 JB |
182 | if (Utils.isUndefined(meterValuesTemplate[index].value)) { |
183 | powerMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxPower); | |
184 | } | |
185 | break; | |
186 | default: | |
187 | logger.error(errMsg); | |
188 | throw Error(errMsg); | |
189 | } | |
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() }, | |
196 | }); | |
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}`); | |
200 | } | |
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, | |
210 | }); | |
211 | } | |
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); | |
218 | throw 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); | |
222 | throw Error(errMsg); | |
223 | } | |
7decf1b6 | 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`; |
c0560973 JB |
225 | const currentMeasurandValues: MeasurandValues = {} as MeasurandValues; |
226 | let maxAmperage: number; | |
7decf1b6 JB |
227 | switch (self.chargingStation.getCurrentOutType()) { |
228 | case CurrentOutType.AC: | |
cb31c873 | 229 | maxAmperage = ACElectricUtils.amperagePerPhaseFromPower(self.chargingStation.getNumberOfPhases(), self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider, self.chargingStation.getVoltageOut()); |
c0560973 JB |
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); | |
237 | } | |
238 | currentMeasurandValues.allPhases = Utils.roundTo((currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / self.chargingStation.getNumberOfPhases(), 2); | |
239 | } | |
240 | break; | |
7decf1b6 | 241 | case CurrentOutType.DC: |
cb31c873 | 242 | maxAmperage = ACElectricUtils.amperageTotalFromPower(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider, self.chargingStation.getVoltageOut()); |
c0560973 JB |
243 | if (Utils.isUndefined(meterValuesTemplate[index].value)) { |
244 | currentMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxAmperage); | |
245 | } | |
246 | break; | |
247 | default: | |
248 | logger.error(errMsg); | |
249 | throw Error(errMsg); | |
250 | } | |
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() }, | |
257 | }); | |
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}`); | |
261 | } | |
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, | |
271 | }); | |
272 | } | |
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); | |
279 | throw 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); | |
283 | throw Error(errMsg); | |
284 | } | |
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; | |
290 | } else { | |
291 | connector.lastEnergyActiveImportRegisterValue = 0; | |
292 | } | |
293 | } | |
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() }, | |
301 | }); | |
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}`); | |
306 | } | |
307 | // Unsupported measurand | |
308 | } else { | |
309 | logger.info(`${self.chargingStation.logPrefix()} Unsupported MeterValues measurand ${meterValuesTemplate[index].measurand ? meterValuesTemplate[index].measurand : OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} on connectorId ${connectorId}`); | |
310 | } | |
311 | } | |
312 | const payload: MeterValuesRequest = { | |
313 | connectorId, | |
314 | transactionId, | |
315 | meterValue, | |
316 | }; | |
bb80986b | 317 | await self.sendMessage(Utils.generateUUID(), payload, MessageType.CALL_MESSAGE, OCPP16RequestCommand.METER_VALUES); |
c0560973 | 318 | } catch (error) { |
bb80986b | 319 | self.handleRequestError(OCPP16RequestCommand.METER_VALUES, error); |
c0560973 JB |
320 | } |
321 | } | |
322 | ||
323 | public async sendError(messageId: string, error: OCPPError, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise<unknown> { | |
324 | // Send error | |
325 | return this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName); | |
326 | } | |
327 | } |