Use the fixed JsonType definition where appropriate
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ServiceUtils.ts
index 23d8a014472d0bc2f5bd3726d9f215db163a397d..2ad75f1d2234725f20cf239557c322f219bbfa04 100644 (file)
@@ -14,12 +14,19 @@ import {
   OCPP16MeterValuePhase,
   OCPP16SampledValue,
 } from '../../../types/ocpp/1.6/MeterValues';
+import {
+  OCPP16IncomingRequestCommand,
+  OCPP16RequestCommand,
+} from '../../../types/ocpp/1.6/Requests';
+import {
+  OCPP16StandardParametersKey,
+  OCPP16SupportedFeatureProfiles,
+} from '../../../types/ocpp/1.6/Configuration';
 
 import type ChargingStation from '../../ChargingStation';
 import Constants from '../../../utils/Constants';
 import { ErrorType } from '../../../types/ocpp/ErrorType';
 import MeasurandValues from '../../../types/MeasurandValues';
-import { OCPP16RequestCommand } from '../../../types/ocpp/1.6/Requests';
 import OCPPError from '../../../exception/OCPPError';
 import Utils from '../../../utils/Utils';
 import logger from '../../../utils/Logger';
@@ -44,6 +51,22 @@ export class OCPP16ServiceUtils {
     }
   }
 
+  public static checkFeatureProfile(
+    chargingStation: ChargingStation,
+    featureProfile: OCPP16SupportedFeatureProfiles,
+    command: OCPP16RequestCommand | OCPP16IncomingRequestCommand
+  ): boolean {
+    if (!chargingStation.hasFeatureProfile(featureProfile)) {
+      logger.warn(
+        `${chargingStation.logPrefix()} Trying to '${command}' without '${featureProfile}' feature enabled in ${
+          OCPP16StandardParametersKey.SupportedFeatureProfiles
+        } in configuration`
+      );
+      return false;
+    }
+    return true;
+  }
+
   public static buildSampledValue(
     sampledValueTemplate: SampledValueTemplate,
     value: number,
@@ -279,12 +302,11 @@ export class OCPP16ServiceUtils {
       } measurand value`;
       const powerMeasurandValues = {} as MeasurandValues;
       const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
-      const maximumPower = Math.round(
-        chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider
+      const connectorMaximumPower = Math.round(
+        chargingStation.getConnectorMaximumAvailablePower(connectorId)
       );
-      const maximumPowerPerPhase = Math.round(
-        chargingStation.getMaximumConfiguredPower() /
-          chargingStation.stationInfo.powerDivider /
+      const connectorMaximumPowerPerPhase = Math.round(
+        chargingStation.getConnectorMaximumAvailablePower(connectorId) /
           chargingStation.getNumberOfPhases()
       );
       switch (chargingStation.getCurrentOutType()) {
@@ -321,15 +343,15 @@ export class OCPP16ServiceUtils {
             powerMeasurandValues.L1 =
               phase1FluctuatedValue ??
               defaultFluctuatedPowerPerPhase ??
-              Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
+              Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
             powerMeasurandValues.L2 =
               phase2FluctuatedValue ??
               defaultFluctuatedPowerPerPhase ??
-              Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
+              Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
             powerMeasurandValues.L3 =
               phase3FluctuatedValue ??
               defaultFluctuatedPowerPerPhase ??
-              Utils.getRandomFloatRounded(maximumPowerPerPhase / unitDivider);
+              Utils.getRandomFloatRounded(connectorMaximumPowerPerPhase / unitDivider);
           } else {
             powerMeasurandValues.L1 = powerSampledValueTemplate.value
               ? Utils.getRandomFloatFluctuatedRounded(
@@ -337,7 +359,7 @@ export class OCPP16ServiceUtils {
                   powerSampledValueTemplate.fluctuationPercent ??
                     Constants.DEFAULT_FLUCTUATION_PERCENT
                 )
-              : Utils.getRandomFloatRounded(maximumPower / unitDivider);
+              : Utils.getRandomFloatRounded(connectorMaximumPower / unitDivider);
             powerMeasurandValues.L2 = 0;
             powerMeasurandValues.L3 = 0;
           }
@@ -353,7 +375,7 @@ export class OCPP16ServiceUtils {
                 powerSampledValueTemplate.fluctuationPercent ??
                   Constants.DEFAULT_FLUCTUATION_PERCENT
               )
-            : Utils.getRandomFloatRounded(maximumPower / unitDivider);
+            : Utils.getRandomFloatRounded(connectorMaximumPower / unitDivider);
           break;
         default:
           logger.error(errMsg);
@@ -366,9 +388,10 @@ export class OCPP16ServiceUtils {
         )
       );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      const maxPowerRounded = Utils.roundTo(maximumPower / unitDivider, 2);
+      const connectorMaximumPowerRounded = Utils.roundTo(connectorMaximumPower / unitDivider, 2);
       if (
-        Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPowerRounded ||
+        Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
+          connectorMaximumPowerRounded ||
         debug
       ) {
         logger.error(
@@ -377,7 +400,7 @@ export class OCPP16ServiceUtils {
             OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
           }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
             meterValue.sampledValue[sampledValuesIndex].value
-          }/${maxPowerRounded}`
+          }/${connectorMaximumPowerRounded}`
         );
       }
       for (
@@ -396,10 +419,13 @@ export class OCPP16ServiceUtils {
           )
         );
         const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
-        const maxPowerPerPhaseRounded = Utils.roundTo(maximumPowerPerPhase / unitDivider, 2);
+        const connectorMaximumPowerPerPhaseRounded = Utils.roundTo(
+          connectorMaximumPowerPerPhase / unitDivider,
+          2
+        );
         if (
           Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
-            maxPowerPerPhaseRounded ||
+            connectorMaximumPowerPerPhaseRounded ||
           debug
         ) {
           logger.error(
@@ -410,7 +436,7 @@ export class OCPP16ServiceUtils {
               meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
             }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
               meterValue.sampledValue[sampledValuesPerPhaseIndex].value
-            }/${maxPowerPerPhaseRounded}`
+            }/${connectorMaximumPowerPerPhaseRounded}`
           );
         }
       }
@@ -455,12 +481,12 @@ export class OCPP16ServiceUtils {
         OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
       } measurand value`;
       const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
-      let maximumAmperage: number;
+      let connectorMaximumAmperage: number;
       switch (chargingStation.getCurrentOutType()) {
         case CurrentType.AC:
-          maximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
+          connectorMaximumAmperage = ACElectricUtils.amperagePerPhaseFromPower(
             chargingStation.getNumberOfPhases(),
-            chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider,
+            chargingStation.getConnectorMaximumAvailablePower(connectorId),
             chargingStation.getVoltageOut()
           );
           if (chargingStation.getNumberOfPhases() === 3) {
@@ -495,15 +521,15 @@ export class OCPP16ServiceUtils {
             currentMeasurandValues.L1 =
               phase1FluctuatedValue ??
               defaultFluctuatedAmperagePerPhase ??
-              Utils.getRandomFloatRounded(maximumAmperage);
+              Utils.getRandomFloatRounded(connectorMaximumAmperage);
             currentMeasurandValues.L2 =
               phase2FluctuatedValue ??
               defaultFluctuatedAmperagePerPhase ??
-              Utils.getRandomFloatRounded(maximumAmperage);
+              Utils.getRandomFloatRounded(connectorMaximumAmperage);
             currentMeasurandValues.L3 =
               phase3FluctuatedValue ??
               defaultFluctuatedAmperagePerPhase ??
-              Utils.getRandomFloatRounded(maximumAmperage);
+              Utils.getRandomFloatRounded(connectorMaximumAmperage);
           } else {
             currentMeasurandValues.L1 = currentSampledValueTemplate.value
               ? Utils.getRandomFloatFluctuatedRounded(
@@ -511,7 +537,7 @@ export class OCPP16ServiceUtils {
                   currentSampledValueTemplate.fluctuationPercent ??
                     Constants.DEFAULT_FLUCTUATION_PERCENT
                 )
-              : Utils.getRandomFloatRounded(maximumAmperage);
+              : Utils.getRandomFloatRounded(connectorMaximumAmperage);
             currentMeasurandValues.L2 = 0;
             currentMeasurandValues.L3 = 0;
           }
@@ -522,8 +548,8 @@ export class OCPP16ServiceUtils {
           );
           break;
         case CurrentType.DC:
-          maximumAmperage = DCElectricUtils.amperage(
-            chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider,
+          connectorMaximumAmperage = DCElectricUtils.amperage(
+            chargingStation.getConnectorMaximumAvailablePower(connectorId),
             chargingStation.getVoltageOut()
           );
           currentMeasurandValues.allPhases = currentSampledValueTemplate.value
@@ -532,7 +558,7 @@ export class OCPP16ServiceUtils {
                 currentSampledValueTemplate.fluctuationPercent ??
                   Constants.DEFAULT_FLUCTUATION_PERCENT
               )
-            : Utils.getRandomFloatRounded(maximumAmperage);
+            : Utils.getRandomFloatRounded(connectorMaximumAmperage);
           break;
         default:
           logger.error(errMsg);
@@ -546,7 +572,8 @@ export class OCPP16ServiceUtils {
       );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
       if (
-        Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maximumAmperage ||
+        Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) >
+          connectorMaximumAmperage ||
         debug
       ) {
         logger.error(
@@ -555,7 +582,7 @@ export class OCPP16ServiceUtils {
             OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
           }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
             meterValue.sampledValue[sampledValuesIndex].value
-          }/${maximumAmperage}`
+          }/${connectorMaximumAmperage}`
         );
       }
       for (
@@ -576,7 +603,7 @@ export class OCPP16ServiceUtils {
         const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
         if (
           Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
-            maximumAmperage ||
+            connectorMaximumAmperage ||
           debug
         ) {
           logger.error(
@@ -587,7 +614,7 @@ export class OCPP16ServiceUtils {
               meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
             }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
               meterValue.sampledValue[sampledValuesPerPhaseIndex].value
-            }/${maximumAmperage}`
+            }/${connectorMaximumAmperage}`
           );
         }
       }
@@ -601,10 +628,8 @@ export class OCPP16ServiceUtils {
       );
       const unitDivider =
         energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
-      const maximumEnergyRounded = Utils.roundTo(
-        ((chargingStation.getMaximumConfiguredPower() / chargingStation.stationInfo.powerDivider) *
-          interval) /
-          (3600 * 1000),
+      const connectorMaximumEnergyRounded = Utils.roundTo(
+        (chargingStation.getConnectorMaximumAvailablePower(connectorId) * interval) / (3600 * 1000),
         2
       );
       const energyValueRounded = energySampledValueTemplate.value
@@ -613,7 +638,7 @@ export class OCPP16ServiceUtils {
             parseInt(energySampledValueTemplate.value),
             energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
           )
-        : Utils.getRandomFloatRounded(maximumEnergyRounded);
+        : Utils.getRandomFloatRounded(connectorMaximumEnergyRounded);
       // Persist previous value on connector
       if (
         connector &&
@@ -639,14 +664,14 @@ export class OCPP16ServiceUtils {
         )
       );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      if (energyValueRounded > maximumEnergyRounded || debug) {
+      if (energyValueRounded > connectorMaximumEnergyRounded || debug) {
         logger.error(
           `${chargingStation.logPrefix()} MeterValues measurand ${
             meterValue.sampledValue[sampledValuesIndex].measurand ??
             OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
           }: connectorId ${connectorId}, transaction ${
             connector.transactionId
-          }, value: ${energyValueRounded}/${maximumEnergyRounded}, duration: ${Utils.roundTo(
+          }, value: ${energyValueRounded}/${connectorMaximumEnergyRounded}, duration: ${Utils.roundTo(
             interval / (3600 * 1000),
             4
           )}h`