refactor: applied changes for pull request
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ServiceUtils.ts
CommitLineData
edd13439 1// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
c8eeb62b 2
130783a7
JB
3import type { JSONSchemaType } from 'ajv';
4
66dd3447 5import { type ChargingStation, ChargingStationUtils } from '../../../charging-station';
268a74bb 6import { OCPPError } from '../../../exception';
e7aeea18 7import {
268a74bb
JB
8 CurrentType,
9 ErrorType,
10 type JsonType,
11 type MeasurandPerPhaseSampledValueTemplates,
12 type MeasurandValues,
e7aeea18
JB
13 MeterValueContext,
14 MeterValueLocation,
15 MeterValueUnit,
66dd3447
JB
16 OCPP16AuthorizationStatus,
17 type OCPP16AuthorizeRequest,
18 type OCPP16AuthorizeResponse,
268a74bb
JB
19 type OCPP16ChargingProfile,
20 type OCPP16IncomingRequestCommand,
27782dbc 21 type OCPP16MeterValue,
e7aeea18
JB
22 OCPP16MeterValueMeasurand,
23 OCPP16MeterValuePhase,
370ae4ee 24 OCPP16RequestCommand,
268a74bb
JB
25 type OCPP16SampledValue,
26 OCPP16StandardParametersKey,
27 type OCPP16SupportedFeatureProfiles,
28 OCPPVersion,
29 type SampledValueTemplate,
30 Voltage,
31} from '../../../types';
60a74391 32import { ACElectricUtils, Constants, DCElectricUtils, Utils, logger } from '../../../utils';
4c3c0d59 33import { OCPPServiceUtils } from '../OCPPServiceUtils';
6ed92bc1 34
7bc31f9c 35export class OCPP16ServiceUtils extends OCPPServiceUtils {
370ae4ee
JB
36 public static checkFeatureProfile(
37 chargingStation: ChargingStation,
38 featureProfile: OCPP16SupportedFeatureProfiles,
39 command: OCPP16RequestCommand | OCPP16IncomingRequestCommand
40 ): boolean {
41 if (!chargingStation.hasFeatureProfile(featureProfile)) {
42 logger.warn(
43 `${chargingStation.logPrefix()} Trying to '${command}' without '${featureProfile}' feature enabled in ${
44 OCPP16StandardParametersKey.SupportedFeatureProfiles
45 } in configuration`
46 );
47 return false;
48 }
49 return true;
50 }
51
78085c42
JB
52 public static buildMeterValue(
53 chargingStation: ChargingStation,
54 connectorId: number,
55 transactionId: number,
56 interval: number,
57 debug = false
58 ): OCPP16MeterValue {
59 const meterValue: OCPP16MeterValue = {
c38f0ced 60 timestamp: new Date(),
78085c42
JB
61 sampledValue: [],
62 };
63 const connector = chargingStation.getConnectorStatus(connectorId);
64 // SoC measurand
ed3d2808 65 const socSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 66 chargingStation,
78085c42
JB
67 connectorId,
68 OCPP16MeterValueMeasurand.STATE_OF_CHARGE
69 );
70 if (socSampledValueTemplate) {
860ef183
JB
71 const socMaximumValue = 100;
72 const socMinimumValue = socSampledValueTemplate.minimumValue ?? 0;
78085c42
JB
73 const socSampledValueTemplateValue = socSampledValueTemplate.value
74 ? Utils.getRandomFloatFluctuatedRounded(
75 parseInt(socSampledValueTemplate.value),
76 socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
77 )
860ef183 78 : Utils.getRandomInteger(socMaximumValue, socMinimumValue);
78085c42
JB
79 meterValue.sampledValue.push(
80 OCPP16ServiceUtils.buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue)
81 );
82 const sampledValuesIndex = meterValue.sampledValue.length - 1;
860ef183
JB
83 if (
84 Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > socMaximumValue ||
85 Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) < socMinimumValue ||
86 debug
87 ) {
78085c42
JB
88 logger.error(
89 `${chargingStation.logPrefix()} MeterValues measurand ${
90 meterValue.sampledValue[sampledValuesIndex].measurand ??
91 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
54ebb82c 92 }: connector id ${connectorId}, transaction id ${
860ef183
JB
93 connector?.transactionId
94 }, value: ${socMinimumValue}/${
78085c42 95 meterValue.sampledValue[sampledValuesIndex].value
860ef183 96 }/${socMaximumValue}}`
78085c42
JB
97 );
98 }
99 }
100 // Voltage measurand
ed3d2808 101 const voltageSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 102 chargingStation,
78085c42
JB
103 connectorId,
104 OCPP16MeterValueMeasurand.VOLTAGE
105 );
106 if (voltageSampledValueTemplate) {
107 const voltageSampledValueTemplateValue = voltageSampledValueTemplate.value
108 ? parseInt(voltageSampledValueTemplate.value)
109 : chargingStation.getVoltageOut();
110 const fluctuationPercent =
111 voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
112 const voltageMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
113 voltageSampledValueTemplateValue,
114 fluctuationPercent
115 );
116 if (
117 chargingStation.getNumberOfPhases() !== 3 ||
118 (chargingStation.getNumberOfPhases() === 3 && chargingStation.getMainVoltageMeterValues())
119 ) {
120 meterValue.sampledValue.push(
121 OCPP16ServiceUtils.buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue)
122 );
123 }
124 for (
125 let phase = 1;
126 chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
127 phase++
128 ) {
129 const phaseLineToNeutralValue = `L${phase}-N`;
130 const voltagePhaseLineToNeutralSampledValueTemplate =
ed3d2808 131 OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 132 chargingStation,
78085c42
JB
133 connectorId,
134 OCPP16MeterValueMeasurand.VOLTAGE,
135 phaseLineToNeutralValue as OCPP16MeterValuePhase
136 );
137 let voltagePhaseLineToNeutralMeasurandValue: number;
138 if (voltagePhaseLineToNeutralSampledValueTemplate) {
139 const voltagePhaseLineToNeutralSampledValueTemplateValue =
140 voltagePhaseLineToNeutralSampledValueTemplate.value
141 ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
142 : chargingStation.getVoltageOut();
143 const fluctuationPhaseToNeutralPercent =
144 voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ??
145 Constants.DEFAULT_FLUCTUATION_PERCENT;
146 voltagePhaseLineToNeutralMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
147 voltagePhaseLineToNeutralSampledValueTemplateValue,
148 fluctuationPhaseToNeutralPercent
149 );
150 }
151 meterValue.sampledValue.push(
152 OCPP16ServiceUtils.buildSampledValue(
153 voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate,
154 voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue,
72092cfc 155 undefined,
78085c42
JB
156 phaseLineToNeutralValue as OCPP16MeterValuePhase
157 )
158 );
159 if (chargingStation.getPhaseLineToLineVoltageMeterValues()) {
160 const phaseLineToLineValue = `L${phase}-L${
161 (phase + 1) % chargingStation.getNumberOfPhases() !== 0
162 ? (phase + 1) % chargingStation.getNumberOfPhases()
163 : chargingStation.getNumberOfPhases()
164 }`;
165 const voltagePhaseLineToLineSampledValueTemplate =
ed3d2808 166 OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 167 chargingStation,
78085c42
JB
168 connectorId,
169 OCPP16MeterValueMeasurand.VOLTAGE,
170 phaseLineToLineValue as OCPP16MeterValuePhase
171 );
172 let voltagePhaseLineToLineMeasurandValue: number;
173 if (voltagePhaseLineToLineSampledValueTemplate) {
174 const voltagePhaseLineToLineSampledValueTemplateValue =
175 voltagePhaseLineToLineSampledValueTemplate.value
176 ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
177 : Voltage.VOLTAGE_400;
178 const fluctuationPhaseLineToLinePercent =
179 voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ??
180 Constants.DEFAULT_FLUCTUATION_PERCENT;
181 voltagePhaseLineToLineMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
182 voltagePhaseLineToLineSampledValueTemplateValue,
183 fluctuationPhaseLineToLinePercent
184 );
185 }
186 const defaultVoltagePhaseLineToLineMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
187 Voltage.VOLTAGE_400,
188 fluctuationPercent
189 );
190 meterValue.sampledValue.push(
191 OCPP16ServiceUtils.buildSampledValue(
192 voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate,
193 voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue,
72092cfc 194 undefined,
78085c42
JB
195 phaseLineToLineValue as OCPP16MeterValuePhase
196 )
197 );
198 }
199 }
200 }
201 // Power.Active.Import measurand
ed3d2808 202 const powerSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 203 chargingStation,
78085c42
JB
204 connectorId,
205 OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT
206 );
abe9e9dd 207 let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
78085c42
JB
208 if (chargingStation.getNumberOfPhases() === 3) {
209 powerPerPhaseSampledValueTemplates = {
ed3d2808 210 L1: OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 211 chargingStation,
78085c42
JB
212 connectorId,
213 OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
214 OCPP16MeterValuePhase.L1_N
215 ),
ed3d2808 216 L2: OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 217 chargingStation,
78085c42
JB
218 connectorId,
219 OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
220 OCPP16MeterValuePhase.L2_N
221 ),
ed3d2808 222 L3: OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 223 chargingStation,
78085c42
JB
224 connectorId,
225 OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
226 OCPP16MeterValuePhase.L3_N
227 ),
228 };
229 }
230 if (powerSampledValueTemplate) {
231 OCPP16ServiceUtils.checkMeasurandPowerDivider(
232 chargingStation,
233 powerSampledValueTemplate.measurand
234 );
fc040c43 235 const errMsg = `MeterValues measurand ${
78085c42
JB
236 powerSampledValueTemplate.measurand ??
237 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
238 }: Unknown ${chargingStation.getCurrentOutType()} currentOutType in template file ${
2484ac1e 239 chargingStation.templateFile
78085c42
JB
240 }, cannot calculate ${
241 powerSampledValueTemplate.measurand ??
242 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
243 } measurand value`;
abe9e9dd 244 const powerMeasurandValues = {} as MeasurandValues;
78085c42 245 const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
1b6498ba
JB
246 const connectorMaximumAvailablePower =
247 chargingStation.getConnectorMaximumAvailablePower(connectorId);
248 const connectorMaximumPower = Math.round(connectorMaximumAvailablePower);
ad8537a7 249 const connectorMaximumPowerPerPhase = Math.round(
1b6498ba 250 connectorMaximumAvailablePower / chargingStation.getNumberOfPhases()
78085c42 251 );
860ef183
JB
252 const connectorMinimumPower = Math.round(powerSampledValueTemplate.minimumValue) ?? 0;
253 const connectorMinimumPowerPerPhase = Math.round(
254 connectorMinimumPower / chargingStation.getNumberOfPhases()
255 );
78085c42
JB
256 switch (chargingStation.getCurrentOutType()) {
257 case CurrentType.AC:
258 if (chargingStation.getNumberOfPhases() === 3) {
259 const defaultFluctuatedPowerPerPhase =
260 powerSampledValueTemplate.value &&
261 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
262 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
263 powerSampledValueTemplate.value,
264 connectorMaximumPower / unitDivider,
265 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 266 ) / chargingStation.getNumberOfPhases(),
78085c42
JB
267 powerSampledValueTemplate.fluctuationPercent ??
268 Constants.DEFAULT_FLUCTUATION_PERCENT
269 );
270 const phase1FluctuatedValue =
271 powerPerPhaseSampledValueTemplates?.L1?.value &&
272 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
273 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
274 powerPerPhaseSampledValueTemplates.L1.value,
275 connectorMaximumPowerPerPhase / unitDivider,
276 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 277 ),
78085c42
JB
278 powerPerPhaseSampledValueTemplates.L1.fluctuationPercent ??
279 Constants.DEFAULT_FLUCTUATION_PERCENT
280 );
281 const phase2FluctuatedValue =
282 powerPerPhaseSampledValueTemplates?.L2?.value &&
283 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
284 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
285 powerPerPhaseSampledValueTemplates.L2.value,
286 connectorMaximumPowerPerPhase / unitDivider,
287 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 288 ),
78085c42
JB
289 powerPerPhaseSampledValueTemplates.L2.fluctuationPercent ??
290 Constants.DEFAULT_FLUCTUATION_PERCENT
291 );
292 const phase3FluctuatedValue =
293 powerPerPhaseSampledValueTemplates?.L3?.value &&
294 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
295 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
296 powerPerPhaseSampledValueTemplates.L3.value,
297 connectorMaximumPowerPerPhase / unitDivider,
298 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 299 ),
78085c42
JB
300 powerPerPhaseSampledValueTemplates.L3.fluctuationPercent ??
301 Constants.DEFAULT_FLUCTUATION_PERCENT
302 );
303 powerMeasurandValues.L1 =
304 phase1FluctuatedValue ??
305 defaultFluctuatedPowerPerPhase ??
860ef183
JB
306 Utils.getRandomFloatRounded(
307 connectorMaximumPowerPerPhase / unitDivider,
308 connectorMinimumPowerPerPhase / unitDivider
309 );
78085c42
JB
310 powerMeasurandValues.L2 =
311 phase2FluctuatedValue ??
312 defaultFluctuatedPowerPerPhase ??
860ef183
JB
313 Utils.getRandomFloatRounded(
314 connectorMaximumPowerPerPhase / unitDivider,
315 connectorMinimumPowerPerPhase / unitDivider
316 );
78085c42
JB
317 powerMeasurandValues.L3 =
318 phase3FluctuatedValue ??
319 defaultFluctuatedPowerPerPhase ??
860ef183
JB
320 Utils.getRandomFloatRounded(
321 connectorMaximumPowerPerPhase / unitDivider,
322 connectorMinimumPowerPerPhase / unitDivider
323 );
78085c42
JB
324 } else {
325 powerMeasurandValues.L1 = powerSampledValueTemplate.value
326 ? Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
327 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
328 powerSampledValueTemplate.value,
329 connectorMaximumPower / unitDivider,
330 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 331 ),
78085c42
JB
332 powerSampledValueTemplate.fluctuationPercent ??
333 Constants.DEFAULT_FLUCTUATION_PERCENT
334 )
860ef183
JB
335 : Utils.getRandomFloatRounded(
336 connectorMaximumPower / unitDivider,
337 connectorMinimumPower / unitDivider
338 );
78085c42
JB
339 powerMeasurandValues.L2 = 0;
340 powerMeasurandValues.L3 = 0;
341 }
342 powerMeasurandValues.allPhases = Utils.roundTo(
343 powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3,
344 2
345 );
346 break;
347 case CurrentType.DC:
348 powerMeasurandValues.allPhases = powerSampledValueTemplate.value
349 ? Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
350 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
351 powerSampledValueTemplate.value,
352 connectorMaximumPower / unitDivider,
353 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 354 ),
78085c42
JB
355 powerSampledValueTemplate.fluctuationPercent ??
356 Constants.DEFAULT_FLUCTUATION_PERCENT
357 )
860ef183
JB
358 : Utils.getRandomFloatRounded(
359 connectorMaximumPower / unitDivider,
360 connectorMinimumPower / unitDivider
361 );
78085c42
JB
362 break;
363 default:
fc040c43 364 logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
78085c42
JB
365 throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
366 }
367 meterValue.sampledValue.push(
368 OCPP16ServiceUtils.buildSampledValue(
369 powerSampledValueTemplate,
370 powerMeasurandValues.allPhases
371 )
372 );
373 const sampledValuesIndex = meterValue.sampledValue.length - 1;
ad8537a7 374 const connectorMaximumPowerRounded = Utils.roundTo(connectorMaximumPower / unitDivider, 2);
860ef183 375 const connectorMinimumPowerRounded = Utils.roundTo(connectorMinimumPower / unitDivider, 2);
78085c42 376 if (
71a77ac2 377 Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
ad8537a7 378 connectorMaximumPowerRounded ||
860ef183
JB
379 Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
380 connectorMinimumPowerRounded ||
78085c42
JB
381 debug
382 ) {
383 logger.error(
384 `${chargingStation.logPrefix()} MeterValues measurand ${
385 meterValue.sampledValue[sampledValuesIndex].measurand ??
386 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
a7529a86 387 }: connector id ${connectorId}, transaction id ${
860ef183
JB
388 connector?.transactionId
389 }, value: ${connectorMinimumPowerRounded}/${
78085c42 390 meterValue.sampledValue[sampledValuesIndex].value
ad8537a7 391 }/${connectorMaximumPowerRounded}`
78085c42
JB
392 );
393 }
394 for (
395 let phase = 1;
396 chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
397 phase++
398 ) {
399 const phaseValue = `L${phase}-N`;
400 meterValue.sampledValue.push(
401 OCPP16ServiceUtils.buildSampledValue(
402 (powerPerPhaseSampledValueTemplates[`L${phase}`] as SampledValueTemplate) ??
403 powerSampledValueTemplate,
404 powerMeasurandValues[`L${phase}`] as number,
72092cfc 405 undefined,
78085c42
JB
406 phaseValue as OCPP16MeterValuePhase
407 )
408 );
409 const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
ad8537a7
JB
410 const connectorMaximumPowerPerPhaseRounded = Utils.roundTo(
411 connectorMaximumPowerPerPhase / unitDivider,
412 2
413 );
860ef183
JB
414 const connectorMinimumPowerPerPhaseRounded = Utils.roundTo(
415 connectorMinimumPowerPerPhase / unitDivider,
416 2
417 );
78085c42
JB
418 if (
419 Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
ad8537a7 420 connectorMaximumPowerPerPhaseRounded ||
860ef183
JB
421 Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
422 connectorMinimumPowerPerPhaseRounded ||
78085c42
JB
423 debug
424 ) {
425 logger.error(
426 `${chargingStation.logPrefix()} MeterValues measurand ${
427 meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
428 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
429 }: phase ${
430 meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
54ebb82c 431 }, connector id ${connectorId}, transaction id ${
860ef183
JB
432 connector?.transactionId
433 }, value: ${connectorMinimumPowerPerPhaseRounded}/${
78085c42 434 meterValue.sampledValue[sampledValuesPerPhaseIndex].value
ad8537a7 435 }/${connectorMaximumPowerPerPhaseRounded}`
78085c42
JB
436 );
437 }
438 }
439 }
440 // Current.Import measurand
ed3d2808 441 const currentSampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 442 chargingStation,
78085c42
JB
443 connectorId,
444 OCPP16MeterValueMeasurand.CURRENT_IMPORT
445 );
abe9e9dd 446 let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
78085c42
JB
447 if (chargingStation.getNumberOfPhases() === 3) {
448 currentPerPhaseSampledValueTemplates = {
ed3d2808 449 L1: OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 450 chargingStation,
78085c42
JB
451 connectorId,
452 OCPP16MeterValueMeasurand.CURRENT_IMPORT,
453 OCPP16MeterValuePhase.L1
454 ),
ed3d2808 455 L2: OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 456 chargingStation,
78085c42
JB
457 connectorId,
458 OCPP16MeterValueMeasurand.CURRENT_IMPORT,
459 OCPP16MeterValuePhase.L2
460 ),
ed3d2808 461 L3: OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab 462 chargingStation,
78085c42
JB
463 connectorId,
464 OCPP16MeterValueMeasurand.CURRENT_IMPORT,
465 OCPP16MeterValuePhase.L3
466 ),
467 };
468 }
469 if (currentSampledValueTemplate) {
470 OCPP16ServiceUtils.checkMeasurandPowerDivider(
471 chargingStation,
472 currentSampledValueTemplate.measurand
473 );
fc040c43 474 const errMsg = `MeterValues measurand ${
78085c42
JB
475 currentSampledValueTemplate.measurand ??
476 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
477 }: Unknown ${chargingStation.getCurrentOutType()} currentOutType in template file ${
2484ac1e 478 chargingStation.templateFile
78085c42
JB
479 }, cannot calculate ${
480 currentSampledValueTemplate.measurand ??
481 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
482 } measurand value`;
abe9e9dd 483 const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
1b6498ba
JB
484 const connectorMaximumAvailablePower =
485 chargingStation.getConnectorMaximumAvailablePower(connectorId);
860ef183 486 const connectorMinimumAmperage = currentSampledValueTemplate.minimumValue ?? 0;
ad8537a7 487 let connectorMaximumAmperage: number;
78085c42
JB
488 switch (chargingStation.getCurrentOutType()) {
489 case CurrentType.AC:
ad8537a7 490 connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
78085c42 491 chargingStation.getNumberOfPhases(),
1b6498ba 492 connectorMaximumAvailablePower,
78085c42
JB
493 chargingStation.getVoltageOut()
494 );
495 if (chargingStation.getNumberOfPhases() === 3) {
496 const defaultFluctuatedAmperagePerPhase =
497 currentSampledValueTemplate.value &&
498 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
499 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
500 currentSampledValueTemplate.value,
501 connectorMaximumAmperage,
502 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
503 ),
78085c42
JB
504 currentSampledValueTemplate.fluctuationPercent ??
505 Constants.DEFAULT_FLUCTUATION_PERCENT
506 );
507 const phase1FluctuatedValue =
508 currentPerPhaseSampledValueTemplates?.L1?.value &&
509 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
510 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
511 currentPerPhaseSampledValueTemplates.L1.value,
512 connectorMaximumAmperage,
513 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 514 ),
78085c42
JB
515 currentPerPhaseSampledValueTemplates.L1.fluctuationPercent ??
516 Constants.DEFAULT_FLUCTUATION_PERCENT
517 );
518 const phase2FluctuatedValue =
519 currentPerPhaseSampledValueTemplates?.L2?.value &&
520 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
521 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
522 currentPerPhaseSampledValueTemplates.L2.value,
523 connectorMaximumAmperage,
524 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 525 ),
78085c42
JB
526 currentPerPhaseSampledValueTemplates.L2.fluctuationPercent ??
527 Constants.DEFAULT_FLUCTUATION_PERCENT
528 );
529 const phase3FluctuatedValue =
530 currentPerPhaseSampledValueTemplates?.L3?.value &&
531 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
532 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
533 currentPerPhaseSampledValueTemplates.L3.value,
534 connectorMaximumAmperage,
535 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
34464008 536 ),
78085c42
JB
537 currentPerPhaseSampledValueTemplates.L3.fluctuationPercent ??
538 Constants.DEFAULT_FLUCTUATION_PERCENT
539 );
540 currentMeasurandValues.L1 =
541 phase1FluctuatedValue ??
542 defaultFluctuatedAmperagePerPhase ??
860ef183 543 Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
78085c42
JB
544 currentMeasurandValues.L2 =
545 phase2FluctuatedValue ??
546 defaultFluctuatedAmperagePerPhase ??
860ef183 547 Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
78085c42
JB
548 currentMeasurandValues.L3 =
549 phase3FluctuatedValue ??
550 defaultFluctuatedAmperagePerPhase ??
860ef183 551 Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
78085c42
JB
552 } else {
553 currentMeasurandValues.L1 = currentSampledValueTemplate.value
554 ? Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
555 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
556 currentSampledValueTemplate.value,
557 connectorMaximumAmperage,
558 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
559 ),
78085c42
JB
560 currentSampledValueTemplate.fluctuationPercent ??
561 Constants.DEFAULT_FLUCTUATION_PERCENT
562 )
860ef183 563 : Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
78085c42
JB
564 currentMeasurandValues.L2 = 0;
565 currentMeasurandValues.L3 = 0;
566 }
567 currentMeasurandValues.allPhases = Utils.roundTo(
568 (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) /
569 chargingStation.getNumberOfPhases(),
570 2
571 );
572 break;
573 case CurrentType.DC:
ad8537a7 574 connectorMaximumAmperage = DCElectricUtils.amperage(
1b6498ba 575 connectorMaximumAvailablePower,
78085c42
JB
576 chargingStation.getVoltageOut()
577 );
578 currentMeasurandValues.allPhases = currentSampledValueTemplate.value
579 ? Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
580 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
581 currentSampledValueTemplate.value,
582 connectorMaximumAmperage,
583 { limitationEnabled: chargingStation.getCustomValueLimitationMeterValues() }
584 ),
78085c42
JB
585 currentSampledValueTemplate.fluctuationPercent ??
586 Constants.DEFAULT_FLUCTUATION_PERCENT
587 )
860ef183 588 : Utils.getRandomFloatRounded(connectorMaximumAmperage, connectorMinimumAmperage);
78085c42
JB
589 break;
590 default:
fc040c43 591 logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
78085c42
JB
592 throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
593 }
594 meterValue.sampledValue.push(
595 OCPP16ServiceUtils.buildSampledValue(
596 currentSampledValueTemplate,
597 currentMeasurandValues.allPhases
598 )
599 );
600 const sampledValuesIndex = meterValue.sampledValue.length - 1;
601 if (
ad8537a7
JB
602 Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
603 connectorMaximumAmperage ||
860ef183
JB
604 Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) <
605 connectorMinimumAmperage ||
78085c42
JB
606 debug
607 ) {
608 logger.error(
609 `${chargingStation.logPrefix()} MeterValues measurand ${
610 meterValue.sampledValue[sampledValuesIndex].measurand ??
611 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
54ebb82c 612 }: connector id ${connectorId}, transaction id ${
860ef183
JB
613 connector?.transactionId
614 }, value: ${connectorMinimumAmperage}/${
78085c42 615 meterValue.sampledValue[sampledValuesIndex].value
ad8537a7 616 }/${connectorMaximumAmperage}`
78085c42
JB
617 );
618 }
619 for (
620 let phase = 1;
621 chargingStation.getNumberOfPhases() === 3 && phase <= chargingStation.getNumberOfPhases();
622 phase++
623 ) {
624 const phaseValue = `L${phase}`;
625 meterValue.sampledValue.push(
626 OCPP16ServiceUtils.buildSampledValue(
627 (currentPerPhaseSampledValueTemplates[phaseValue] as SampledValueTemplate) ??
628 currentSampledValueTemplate,
629 currentMeasurandValues[phaseValue] as number,
72092cfc 630 undefined,
78085c42
JB
631 phaseValue as OCPP16MeterValuePhase
632 )
633 );
634 const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
635 if (
636 Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
ad8537a7 637 connectorMaximumAmperage ||
860ef183
JB
638 Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) <
639 connectorMinimumAmperage ||
78085c42
JB
640 debug
641 ) {
642 logger.error(
643 `${chargingStation.logPrefix()} MeterValues measurand ${
644 meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
645 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
646 }: phase ${
647 meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
54ebb82c 648 }, connector id ${connectorId}, transaction id ${
860ef183
JB
649 connector?.transactionId
650 }, value: ${connectorMinimumAmperage}/${
78085c42 651 meterValue.sampledValue[sampledValuesPerPhaseIndex].value
ad8537a7 652 }/${connectorMaximumAmperage}`
78085c42
JB
653 );
654 }
655 }
656 }
657 // Energy.Active.Import.Register measurand (default)
ed3d2808 658 const energySampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab
JB
659 chargingStation,
660 connectorId
661 );
78085c42
JB
662 if (energySampledValueTemplate) {
663 OCPP16ServiceUtils.checkMeasurandPowerDivider(
664 chargingStation,
665 energySampledValueTemplate.measurand
666 );
667 const unitDivider =
668 energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
1b6498ba
JB
669 const connectorMaximumAvailablePower =
670 chargingStation.getConnectorMaximumAvailablePower(connectorId);
ad8537a7 671 const connectorMaximumEnergyRounded = Utils.roundTo(
1b6498ba 672 (connectorMaximumAvailablePower * interval) / (3600 * 1000),
78085c42
JB
673 2
674 );
675 const energyValueRounded = energySampledValueTemplate.value
676 ? // Cumulate the fluctuated value around the static one
677 Utils.getRandomFloatFluctuatedRounded(
7bc31f9c
JB
678 OCPP16ServiceUtils.getLimitFromSampledValueTemplateCustomValue(
679 energySampledValueTemplate.value,
680 connectorMaximumEnergyRounded,
681 {
682 limitationEnabled: chargingStation.getCustomValueLimitationMeterValues(),
683 unitMultiplier: unitDivider,
684 }
34464008 685 ),
78085c42
JB
686 energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
687 )
ad8537a7 688 : Utils.getRandomFloatRounded(connectorMaximumEnergyRounded);
78085c42
JB
689 // Persist previous value on connector
690 if (
691 connector &&
3a13fc92 692 Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) === false &&
78085c42 693 connector.energyActiveImportRegisterValue >= 0 &&
3a13fc92 694 Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) === false &&
78085c42
JB
695 connector.transactionEnergyActiveImportRegisterValue >= 0
696 ) {
697 connector.energyActiveImportRegisterValue += energyValueRounded;
698 connector.transactionEnergyActiveImportRegisterValue += energyValueRounded;
699 } else {
700 connector.energyActiveImportRegisterValue = 0;
701 connector.transactionEnergyActiveImportRegisterValue = 0;
702 }
703 meterValue.sampledValue.push(
704 OCPP16ServiceUtils.buildSampledValue(
705 energySampledValueTemplate,
706 Utils.roundTo(
707 chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) /
708 unitDivider,
709 2
710 )
711 )
712 );
713 const sampledValuesIndex = meterValue.sampledValue.length - 1;
ad8537a7 714 if (energyValueRounded > connectorMaximumEnergyRounded || debug) {
78085c42
JB
715 logger.error(
716 `${chargingStation.logPrefix()} MeterValues measurand ${
717 meterValue.sampledValue[sampledValuesIndex].measurand ??
718 OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
54ebb82c 719 }: connector id ${connectorId}, transaction id ${
72092cfc 720 connector?.transactionId
ad8537a7 721 }, value: ${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${Utils.roundTo(
78085c42
JB
722 interval / (3600 * 1000),
723 4
724 )}h`
725 );
726 }
727 }
728 return meterValue;
729 }
730
e7aeea18
JB
731 public static buildTransactionBeginMeterValue(
732 chargingStation: ChargingStation,
733 connectorId: number,
78085c42 734 meterStart: number
e7aeea18 735 ): OCPP16MeterValue {
fd0c36fa 736 const meterValue: OCPP16MeterValue = {
c38f0ced 737 timestamp: new Date(),
fd0c36fa
JB
738 sampledValue: [],
739 };
9ccca265 740 // Energy.Active.Import.Register measurand (default)
ed3d2808 741 const sampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab
JB
742 chargingStation,
743 connectorId
744 );
9ccca265 745 const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
e7aeea18
JB
746 meterValue.sampledValue.push(
747 OCPP16ServiceUtils.buildSampledValue(
748 sampledValueTemplate,
2040a613 749 Utils.roundTo((meterStart ?? 0) / unitDivider, 4),
e7aeea18
JB
750 MeterValueContext.TRANSACTION_BEGIN
751 )
752 );
fd0c36fa
JB
753 return meterValue;
754 }
755
e7aeea18
JB
756 public static buildTransactionEndMeterValue(
757 chargingStation: ChargingStation,
758 connectorId: number,
78085c42 759 meterStop: number
e7aeea18 760 ): OCPP16MeterValue {
fd0c36fa 761 const meterValue: OCPP16MeterValue = {
c38f0ced 762 timestamp: new Date(),
fd0c36fa
JB
763 sampledValue: [],
764 };
9ccca265 765 // Energy.Active.Import.Register measurand (default)
ed3d2808 766 const sampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
492cf6ab
JB
767 chargingStation,
768 connectorId
769 );
9ccca265 770 const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
e7aeea18
JB
771 meterValue.sampledValue.push(
772 OCPP16ServiceUtils.buildSampledValue(
773 sampledValueTemplate,
2040a613 774 Utils.roundTo((meterStop ?? 0) / unitDivider, 4),
e7aeea18
JB
775 MeterValueContext.TRANSACTION_END
776 )
777 );
fd0c36fa
JB
778 return meterValue;
779 }
780
e7aeea18
JB
781 public static buildTransactionDataMeterValues(
782 transactionBeginMeterValue: OCPP16MeterValue,
783 transactionEndMeterValue: OCPP16MeterValue
784 ): OCPP16MeterValue[] {
fd0c36fa
JB
785 const meterValues: OCPP16MeterValue[] = [];
786 meterValues.push(transactionBeginMeterValue);
787 meterValues.push(transactionEndMeterValue);
788 return meterValues;
789 }
7bc31f9c 790
ed3d2808
JB
791 public static setChargingProfile(
792 chargingStation: ChargingStation,
793 connectorId: number,
884a6fdf 794 cp: OCPP16ChargingProfile
ed3d2808 795 ): void {
72092cfc
JB
796 if (
797 Utils.isNullOrUndefined(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)
798 ) {
ed3d2808 799 logger.error(
54ebb82c 800 `${chargingStation.logPrefix()} Trying to set a charging profile on connector id ${connectorId} with an uninitialized charging profiles array attribute, applying deferred initialization`
ed3d2808
JB
801 );
802 chargingStation.getConnectorStatus(connectorId).chargingProfiles = [];
803 }
72092cfc
JB
804 if (
805 Array.isArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles) === false
806 ) {
ed3d2808 807 logger.error(
54ebb82c 808 `${chargingStation.logPrefix()} Trying to set a charging profile on connector id ${connectorId} with an improper attribute type for the charging profiles array, applying proper type initialization`
ed3d2808
JB
809 );
810 chargingStation.getConnectorStatus(connectorId).chargingProfiles = [];
811 }
812 let cpReplaced = false;
53ac516c 813 if (Utils.isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)) {
ed3d2808
JB
814 chargingStation
815 .getConnectorStatus(connectorId)
72092cfc 816 ?.chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
ed3d2808
JB
817 if (
818 chargingProfile.chargingProfileId === cp.chargingProfileId ||
819 (chargingProfile.stackLevel === cp.stackLevel &&
820 chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)
821 ) {
822 chargingStation.getConnectorStatus(connectorId).chargingProfiles[index] = cp;
823 cpReplaced = true;
824 }
825 });
826 }
72092cfc 827 !cpReplaced && chargingStation.getConnectorStatus(connectorId)?.chargingProfiles?.push(cp);
ed3d2808
JB
828 }
829
1b271a54
JB
830 public static parseJsonSchemaFile<T extends JsonType>(
831 relativePath: string,
832 moduleName?: string,
833 methodName?: string
834 ): JSONSchemaType<T> {
7164966d 835 return super.parseJsonSchemaFile<T>(
51022aa0 836 relativePath,
1b271a54
JB
837 OCPPVersion.VERSION_16,
838 moduleName,
839 methodName
7164966d 840 );
130783a7
JB
841 }
842
66dd3447
JB
843 public static async isIdTagAuthorized(
844 chargingStation: ChargingStation,
845 connectorId: number,
846 idTag: string,
847 parentIdTag?: string
848 ): Promise<boolean> {
849 let authorized = false;
850 const connectorStatus = chargingStation.getConnectorStatus(connectorId);
851 if (OCPP16ServiceUtils.isIdTagLocalAuthorized(chargingStation, idTag)) {
852 connectorStatus.localAuthorizeIdTag = idTag;
853 connectorStatus.idTagLocalAuthorized = true;
854 authorized = true;
855 } else if (chargingStation.getMustAuthorizeAtRemoteStart() === true) {
856 connectorStatus.authorizeIdTag = idTag;
857 authorized = await OCPP16ServiceUtils.isIdTagRemoteAuthorized(chargingStation, idTag);
858 } else {
859 logger.warn(
860 `${chargingStation.logPrefix()} The charging station configuration expects authorize at
861 remote start transaction but local authorization or authorize isn't enabled`
862 );
863 }
864 return authorized;
865 }
866
7bc31f9c
JB
867 private static buildSampledValue(
868 sampledValueTemplate: SampledValueTemplate,
869 value: number,
870 context?: MeterValueContext,
871 phase?: OCPP16MeterValuePhase
872 ): OCPP16SampledValue {
873 const sampledValueValue = value ?? sampledValueTemplate?.value ?? null;
874 const sampledValueContext = context ?? sampledValueTemplate?.context ?? null;
875 const sampledValueLocation =
876 sampledValueTemplate?.location ??
877 OCPP16ServiceUtils.getMeasurandDefaultLocation(sampledValueTemplate?.measurand ?? null);
878 const sampledValuePhase = phase ?? sampledValueTemplate?.phase ?? null;
879 return {
880 ...(!Utils.isNullOrUndefined(sampledValueTemplate.unit) && {
881 unit: sampledValueTemplate.unit,
882 }),
883 ...(!Utils.isNullOrUndefined(sampledValueContext) && { context: sampledValueContext }),
884 ...(!Utils.isNullOrUndefined(sampledValueTemplate.measurand) && {
885 measurand: sampledValueTemplate.measurand,
886 }),
887 ...(!Utils.isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation }),
888 ...(!Utils.isNullOrUndefined(sampledValueValue) && { value: sampledValueValue.toString() }),
889 ...(!Utils.isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase }),
890 };
891 }
892
893 private static checkMeasurandPowerDivider(
894 chargingStation: ChargingStation,
895 measurandType: OCPP16MeterValueMeasurand
896 ): void {
fa7bccf4 897 if (Utils.isUndefined(chargingStation.powerDivider)) {
fc040c43 898 const errMsg = `MeterValues measurand ${
7bc31f9c
JB
899 measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
900 }: powerDivider is undefined`;
fc040c43 901 logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
7bc31f9c 902 throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
fa7bccf4 903 } else if (chargingStation?.powerDivider <= 0) {
fc040c43 904 const errMsg = `MeterValues measurand ${
7bc31f9c 905 measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
fa7bccf4 906 }: powerDivider have zero or below value ${chargingStation.powerDivider}`;
fc040c43 907 logger.error(`${chargingStation.logPrefix()} ${errMsg}`);
7bc31f9c
JB
908 throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
909 }
910 }
911
912 private static getMeasurandDefaultLocation(
913 measurandType: OCPP16MeterValueMeasurand
914 ): MeterValueLocation | undefined {
915 switch (measurandType) {
916 case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
917 return MeterValueLocation.EV;
918 }
919 }
920
921 private static getMeasurandDefaultUnit(
922 measurandType: OCPP16MeterValueMeasurand
923 ): MeterValueUnit | undefined {
924 switch (measurandType) {
925 case OCPP16MeterValueMeasurand.CURRENT_EXPORT:
926 case OCPP16MeterValueMeasurand.CURRENT_IMPORT:
927 case OCPP16MeterValueMeasurand.CURRENT_OFFERED:
928 return MeterValueUnit.AMP;
929 case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_EXPORT_REGISTER:
930 case OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER:
931 return MeterValueUnit.WATT_HOUR;
932 case OCPP16MeterValueMeasurand.POWER_ACTIVE_EXPORT:
933 case OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT:
934 case OCPP16MeterValueMeasurand.POWER_OFFERED:
935 return MeterValueUnit.WATT;
936 case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
937 return MeterValueUnit.PERCENT;
938 case OCPP16MeterValueMeasurand.VOLTAGE:
939 return MeterValueUnit.VOLT;
940 }
941 }
66dd3447
JB
942
943 private static isIdTagLocalAuthorized(chargingStation: ChargingStation, idTag: string): boolean {
944 return (
945 chargingStation.getLocalAuthListEnabled() === true &&
946 chargingStation.hasIdTags() === true &&
947 Utils.isNotEmptyString(
948 chargingStation.idTagsCache
949 .getIdTags(ChargingStationUtils.getIdTagsFile(chargingStation.stationInfo))
950 ?.find((tag) => tag === idTag)
951 )
952 );
953 }
954
955 private static async isIdTagRemoteAuthorized(
956 chargingStation: ChargingStation,
957 idTag: string
958 ): Promise<boolean> {
959 const authorizeResponse: OCPP16AuthorizeResponse =
960 await chargingStation.ocppRequestService.requestHandler<
961 OCPP16AuthorizeRequest,
962 OCPP16AuthorizeResponse
963 >(chargingStation, OCPP16RequestCommand.AUTHORIZE, {
964 idTag: idTag,
965 });
966 return authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED;
967 }
6ed92bc1 968}